sample-calculator

元件:

  • index.js(進入點)

  • Controller\RootController.js(根組件)(放置業務邏輯)

  • View\RootView.js(父組件介面繪製)

  • View\NumButton.js(子組件介面繪製)

1.index.js

//進入點的程式基本不更動,是固定架構的寫法
//但此處用RootController取代app做為根組件

import {AppRegistry} from 'react-native';
import RootController from './Controller/RootController';
import {name as appName} from './app.json';

AppRegistry.registerComponent(appName, () => RootController);

2.RootController.js

//根組件

import React, { Component } from 'react';
//載入view的父元件
import RootView from './../View/RootView';

export default class RootController extends Component{
    render(){
        //將Controller整個傳入RootView,使其可使用所有在Controller中的屬性或方法
        //用ref可在父元件調用子元件的方法和屬性
        return (<RootView controller={this} ref="rootView"/>);
    }

    //按下調換按鈕後執行的動作邏輯
    //此處的函式只做呼叫的邏輯(放入參數和執行),真正的程式在view內
    change(){
        if (this.refs.rootView.isDollarToRMB) {
            this.refs.rootView.exchange(false);
        }else{
            this.refs.rootView.exchange(true);
        }
    }

    //按下計算機的相關按鈕(數字、小數點、運算符號…等)
    //真正的程式在view內
    click(title){
        if (title==="0"||title==="1"||title==="2"||title==="3"||title==="4"
            ||title==="5"||title==="6"||title==="7"||title==="8"||title==="9"||title===".") {
            this.refs.rootView.inputNum(title);
        }else if(title==="delete"){
            this.refs.rootView.delete();
        }else if(title==="C"){
            this.refs.rootView.clear();
        }else if(title==="-"){
            this.refs.rootView.sub();
        }else if(title==="+"){
            this.refs.rootView.add();
        }else if(title==="="){
            this.refs.rootView.rate();
        }
    }
}

3.RootView.js

import React, { Component } from 'react';
import {
  StyleSheet,
  View,
  Text,
  Dimensions,
  TouchableHighlight,
  Image
} from 'react-native';
import NumButton from './NumButton';
const rate = 6.7;
export default class RootView extends Component{
    isDollarToRMB = true;

    //參數isDaller是在controller中賦值
    exchange(isDaller){
        if (!isDaller) {
            this.setState({
                topTitle:"从人民币",
                bottomTitle:"到美元",
                topNum:"0$",
                bottomNum:"0¥",
            });
        }
        else{
            this.setState({
                topTitle:"从美元",
                bottomTitle:"到人民币",
                topNum:"0$",
                bottomNum:"0¥",
            });
        }
        this.isDollarToRMB = isDaller;
    }

    inputNum(title){
        let str = this.state.topNum.slice(0,-1);
        if (title===".") {
            if (str.indexOf(".")===-1) {
                if (this.isDollarToRMB) {
                    this.setState({
                        topNum:Number(str)+title+"$",
                    });
                }else{
                    this.setState({
                        topNum:Number(str)+title+"¥",
                    });
                }    
            }else{
                return;
            }
        }else{
            if (this.isDollarToRMB) {
                this.setState({
                    topNum:Number(str+title)+"$",
                });
            }else{
                this.setState({
                    topNum:Number(str+title)+"¥",
                });
            }
        }

    }

    delete(){
        let str = this.state.topNum.slice(0,-1);
        if (str.length===1) {
            if (this.isDollarToRMB) {
                this.setState({
                    topNum:"0$",
                });
            }else{
                this.setState({
                    topNum:"0¥",
                });
            }
        }else{
            if (this.isDollarToRMB) {
                this.setState({
                    topNum:str.slice(0,-1)+"$",
                });
            }else{
                this.setState({
                    topNum:str.slice(0,-1)+"¥",
                });
            }        
        }
    }

    clear(){
        this.setState({
            topNum:"0$",
            bottomNum:"0¥",
        });
    }

    sub(){
        let str = this.state.topNum.slice(0,-1);
        if (Number(str)<1) {
            return;
        }else{
            if (this.isDollarToRMB) {
                this.setState({
                    //此處的程式單純將數值減1
                    topNum:(Number(str)-1).toFixed(2)+"$",
                });
            }else{
                this.setState({
                    topNum:Number(str).toFixed(2)-1+"¥",
                });
            }        
        }
    }

    add(){
        let str = this.state.topNum.slice(0,-1);
        if (this.isDollarToRMB) {
            this.setState({
                topNum:(Number(str)+1).toFixed(2)+"$",
            });
        }else{
            this.setState({
                topNum:(Number(str)+1).toFixed(2)+"¥",
            });
        }        
    }

    rate(){
        let str = this.state.topNum.slice(0,-1);
        if (this.isDollarToRMB) {
            this.setState({
                bottomNum:(Number(str)*rate).toFixed(2)+"¥",
            });
        }else{
            this.setState({
                bottomNum:(Number(str)/rate).toFixed(2)+"$",
            });
        }    
    }

    constructor(props){
        super(props);
        //view內放state
        this.state = {
            topTitle:"从美元",
            topNum:"0$",
            bottomTitle:"到人民币",
            bottomNum:"0¥",
            rootViewStyle:rootViewStyle1,
            lineViewHeight:25
        };
        let titles = ["1","2","3","delete","4","5","6","0","7","8","9",".","C","-","+","="];
        //儲存按鈕的jsx
        let array = new Array();
        for (var i = 1; i <= 16; i++) {
            let element;
            if (i==4) {
                //再把controller及相關屬性往下傳
                element = (<NumButton style={this.state.rootViewStyle.buttonStyle} key={i} title={titles[i-1]} model="image" controller={this.props.controller} />);
            }else if(i==13||i==16){
                element = (<NumButton style={[this.state.rootViewStyle.buttonStyle,{backgroundColor:"rgb(234,86,37)"}]} key={i} title={titles[i-1]} model="text" controller={this.props.controller} />);
            }
            else{
                element = (<NumButton style={this.state.rootViewStyle.buttonStyle} key={i} title={titles[i-1]} model="text" controller={this.props.controller} />);
            }
            array.push(element);
        }
        this.buttons = array;


    }
    render(){
        return(
            //onLayout觸發切換style(用了效能好,不用也可)
            <View style={this.state.rootViewStyle.rootView} onLayout={this._onLayout}>
                <View style={this.state.rootViewStyle.screenView}>
                    <Text style={this.state.rootViewStyle.titleStyle}>{this.state.topTitle}</Text>
                    <Text style={this.state.rootViewStyle.numberStyle}>{this.state.topNum}</Text>
                    <View style={this.state.rootViewStyle.exchangeView}>
                    //按下後觸發controller的change
                        <TouchableHighlight underlayColor="rgb(234,86,37)" onPress={()=>{
                            this.props.controller.change();
                        }}>
                            <Image style={this.state.rootViewStyle.image} source={require("../src/exchange.png")}/>
                        </TouchableHighlight>
                        <View style={this.state.rootViewStyle.lineView}></View>
                    </View>
                    <Text style={[this.state.rootViewStyle.titleStyle,{marginTop:5}]}>{this.state.bottomTitle}</Text>
                    <Text style={this.state.rootViewStyle.numberStyle}>{this.state.bottomNum}</Text>
                </View>
                <View style={this.state.rootViewStyle.keyboardView}>
                    //一排四個按鈕
                    <View style={this.state.rootViewStyle.rowView}>
                        {
                            this.buttons.slice(0,4)
                        }
                    </View>
                    <View style={this.state.rootViewStyle.rowView}>
                        {
                            this. buttons.slice(4,8)
                        }
                    </View>
                    <View style={this.state.rootViewStyle.rowView}>
                        {
                            this.buttons.slice(8,12)
                        }
                    </View>
                    <View style={this.state.rootViewStyle.rowView}>
                        {
                            this.buttons.slice(12,16)
                        }
                    </View>
                </View>
            </View>
        );
    }

    //轉換手機方向時,變更style
    _onLayout=()=>{
        let {width,height} = Dimensions.get("window");
        if (width>height) {
            this.setState({
                rootViewStyle:rootViewStyle2,
                lineViewHeight:0
            });
        }else{
            this.setState({
                rootViewStyle:rootViewStyle1,
                lineViewHeight:25
            });
        }
    }
}

//手機垂直擺放的格式
let rootViewStyle1 = StyleSheet.create({
    screenView:{
        backgroundColor:"rgb(234,86,37)",
        //佔畫面1/3
        flex:1
    },
    keyboardView:{
        backgroundColor:'rgb(38,41,42)',
        //佔畫面2/3
        flex:2
    },
    rootView:{
        flex:1
    },
    titleStyle:{
        marginRight:15,
        fontSize:17,
        textAlign:'right',
        color:"white",
        marginTop:25
    },
    numberStyle:{
        fontSize:30,
        textAlign:'right',
        marginRight:15,
        marginTop:5,
        color:'white'
    },
    exchangeView:{
        height:20,
        flexDirection:'row'
    },
    image:{
        width:18,
        height:18,
        marginTop:1,
        marginLeft:100,
    },
    //橫向直線
    lineView:{
        height:1,
        backgroundColor:'white',
        flex:1,
        marginTop:9,
        marginLeft:20
    },
    rowView:{
        flex:1,
        flexDirection:'row'
    },
    buttonStyle:{
        flex:1,
    }
});

let rootViewStyle2 = StyleSheet.create({
    screenView:{
        backgroundColor:"rgb(234,86,37)",
        flex:3
    },
    keyboardView:{
        backgroundColor:'rgb(38,41,42)',
        flex:5
    },
    rootView:{
        flex:1
    },
    titleStyle:{
        marginRight:15,
        fontSize:13,
        textAlign:'right',
        color:"white",
        marginTop:5
    },
    numberStyle:{
        fontSize:22,
        textAlign:'right',
        marginRight:15,
        marginTop:2,
        color:'white'
    },
    exchangeView:{
        height:20,
        flexDirection:'row'
    },
    image:{
        width:14,
        height:14,
        marginTop:1,
        marginLeft:300,
    },
    lineView:{
        height:1,
        backgroundColor:'white',
        flex:1,
        marginTop:7,
        marginLeft:20
    },
    rowView:{
        flex:1,
        flexDirection:'row'
    },
    buttonStyle:{
        flex:1,
    }
});

4.NumButton.js

import React, { Component } from 'react';
import {
  StyleSheet,
  View,
  Text,
  TouchableHighlight,
  Image
} from 'react-native';

export default class NumButton extends Component{
    render(){
        //當按下的按鈕是文字格式時,render出的jsx語法
        if (this.props.model === "text") {
            return(
                <TouchableHighlight style={[this.props.style,numberStyle.container]} onPress={()=>{
                    this.props.controller.click(this.props.title);
                }}>
                    <Text style={numberStyle.text}>{this.props.title}</Text>
                </TouchableHighlight>
            );
        }else{
            //按下是圖片時
            return(
                <TouchableHighlight style={[this.props.style,numberStyle.container]} onPress={()=>{
                    this.props.controller.click(this.props.title);
                }}>
                    <View style={numberStyle.imageView}>
                        <Image style={numberStyle.imageStyle} source={require("../src/delete.png")}/>
                    </View>
                </TouchableHighlight>
            );            
        }
    }
}

let numberStyle = StyleSheet.create({
    container:{
        flexDirection:'row'
    },
    text:{
        color:"white",
        textAlign:'center',
        flex:1,
        alignSelf:'center',
        fontSize:27
    },
    imageView:{
        flexDirection:'row',
        flex:1,
        justifyContent:'center'
    },
    imageStyle:{
        alignSelf:'center',
    }
});

Last updated