【Android实验】UI设计-Android计算器

实验目的

自主完成一个简单APP的设计工作,综合应用已经学到的Android UI设计技巧,重点注意合理使用布局

实验要求

  1. 完成一个计算器的设计,可以以手机自带的计算器为参考。设计过程中,注意考虑界面的美观性,不同机型的适应性,以及功能的完备性。
  2. 注意结合Activity的生命周期,考虑不同情况下计算器的界面状态。
  3. 如有余力,可以考虑实现一个高精度科学计算型的计算器。

实验过程

1. 界面设计

界面仿照自己手机中计算器界面进行了设计,采用的布局是线性布局,其中比较特殊的布局是最后两行的布局,由于“=”键占用两个位置,所以采用vertical和horizontal相互配合的方式进行。

界面的展示如下:

界面代码(activity_caculator.xml):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:background="@drawable/a5"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="2"
        android:orientation="vertical"
        android:focusableInTouchMode="true">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Calculator"
            android:textStyle="italic"
            android:textAlignment="center"
            android:textSize="20sp" />

        <EditText
            android:id="@+id/et_input"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="0"
            android:enabled="true"
            android:textAlignment="textEnd"
            android:textSize="30sp"
            android:background="@null"/>
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:orientation="horizontal"
        android:weightSum="4">

        <Button style="?android:attr/buttonStyle"
            android:id="@+id/btn_clear"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="#FFE4C4"
            android:text="C"
            android:textAlignment="center"
            android:textSize="20sp"/>

        <Button style="?android:attr/buttonStyle"
            android:id="@+id/btn_divide"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="#FFE4C4"
            android:text="/"
            android:textAlignment="center"
            android:textSize="20sp"/>

        <Button style="?android:attr/buttonStyle"
            android:id="@+id/btn_times"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="#FFE4C4"
            android:text="*"
            android:textAlignment="center"
            android:textSize="20sp"/>

        <Button
            android:id="@+id/btn_delete"
            style="?android:attr/buttonStyle"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="#FFE4C4"
            android:text="DEL"
            android:textAlignment="center"
            android:textSize="20sp" />
    </LinearLayout>


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:orientation="horizontal"
        android:layout_weight="1"
        android:weightSum="4">

        <Button style="?android:attr/buttonStyle"
            android:id="@+id/btn_7"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="#FDF5E6"
            android:text="7"
            android:textAlignment="center"
            android:textSize="20sp"/>

        <Button
            android:id="@+id/btn_8"
            style="?android:attr/buttonStyle"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="#FDF5E6"
            android:text="8"
            android:textAlignment="center"
            android:textSize="20sp" />

        <Button style="?android:attr/buttonStyle"
            android:id="@+id/btn_9"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="#FDF5E6"
            android:text="9"
            android:textAlignment="center"
            android:textSize="20sp"/>

        <Button style="?android:attr/buttonStyle"
            android:id="@+id/btn_sub"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:background="#FFC0CB"
            android:layout_weight="1"
            android:text="-"
            android:textAlignment="center"
            android:textSize="20sp"/>
    </LinearLayout>


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:orientation="horizontal"
        android:layout_weight="1"
        android:weightSum="4">

        <Button style="?android:attr/buttonStyle"
            android:id="@+id/btn_4"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="#FDF5E6"
            android:text="4"
            android:textAlignment="center"
            android:textSize="20sp"/>

        <Button
            android:id="@+id/btn_5"
            style="?android:attr/buttonStyle"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="#FDF5E6"
            android:text="5"
            android:textAlignment="center"
            android:textSize="20sp" />

        <Button
            android:id="@+id/btn_6"
            style="?android:attr/buttonStyle"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="#FDF5E6"
            android:text="6"
            android:textAlignment="center"
            android:textSize="20sp" />

        <Button
            android:id="@+id/btn_add"
            style="?android:attr/buttonStyle"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="#FFC0CB"
            android:text="+"
            android:textAlignment="center"
            android:textSize="20sp" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:orientation="horizontal"
        android:layout_weight="2"
        android:weightSum="4">

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:layout_weight="1">

            <Button style="?android:attr/buttonStyle"
                android:id="@+id/btn_1"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:background="#FDF5E6"
                android:text="1"
                android:textAlignment="center"
                android:textSize="20sp"/>

            <Button style="?android:attr/buttonStyle"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="%"
                android:textAlignment="center"
                android:background="#FDF5E6"
                android:layout_weight="1"
                android:id="@+id/btn_remainder"
                android:textSize="20sp"/>
        </LinearLayout>
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:layout_weight="1">

            <Button style="?android:attr/buttonStyle"
                android:id="@+id/btn_2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:background="#FDF5E6"
                android:text="2"
                android:textAlignment="center"
                android:textSize="20sp"/>

            <Button style="?android:attr/buttonStyle"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="0"
                android:textAlignment="center"
                android:background="#FDF5E6"
                android:layout_weight="1"
                android:id="@+id/btn_0"
                android:textSize="20sp"/>
        </LinearLayout>
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:layout_weight="1">
            <Button style="?android:attr/buttonStyle"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="3"
                android:textAlignment="center"
                android:background="#FDF5E6"
                android:layout_weight="1"
                android:id="@+id/btn_3"
                android:textSize="20sp"/>

            <Button
                android:id="@+id/btn_point"
                style="?android:attr/buttonStyle"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:background="#FDF5E6"
                android:text="."
                android:textAlignment="center"
                android:textSize="20sp" />
        </LinearLayout>
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:layout_weight="1">
            <Button style="?android:attr/buttonStyle"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="="
                android:textAlignment="center"
                android:background="#FFC0CB"
                android:layout_weight="1"
                android:id="@+id/btn_equal"
                android:textSize="20sp"/>
        </LinearLayout>

    </LinearLayout>
</LinearLayout>

在界面设计的过程中,感觉android:layout_weight是一个比较重要的属性,整个界面的按比例排布都需要这个属性来决定,如果用绝对位置会导致翻转以后,计算器按钮无法按比例进行填充。

另外界面的一个特点就是没有了ActionBar,这个通过设置Style.xml中的parent属性,从而可以改变。

Style.xml文件如下:

<resources>
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>
</resources>

另外的app命令以及图标替换在AndroidManifest.xml文件中更改:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.administrator.calculator">

    <application
        android:allowBackup="true"
        android:icon="@drawable/pjthis"
        android:label="PjCalc"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.AppCompat.Light.NoActionBar">
        <activity android:name=".Caculator">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

修改APP名称在android:label属性中修改,APP图标在android:icon中修改,其中android:theme改为NoActionBar可以将头部的标题去掉,增大空间。在LinearLayout中修改android:backgroud可以对背景进行修改,这里换成了一个自定义背景。

2. 功能设计

进行事件响应的主体为:Calculator.java

对界面事件的获取以及处理主要由该文件处理:

代码如下:

package com.example.administrator.calculator;

import android.content.Context;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;


public class Caculator extends AppCompatActivity implements View.OnClickListener {

    Button bt_0, bt_1, bt_2, bt_3, bt_4, bt_5, bt_6, bt_7, bt_8, bt_9;
    Button bt_clear, bt_divide, bt_times, bt_delete, bt_add, bt_sub, bt_equal, bt_remainder, bt_point;
    private EditText et_input;

    private StringBuilder fomula = new StringBuilder();

    private void initP() {
        bt_0 = (Button) findViewById(R.id.btn_0);
        bt_1 = (Button) findViewById(R.id.btn_1);
        bt_2 = (Button) findViewById(R.id.btn_2);
        bt_3 = (Button) findViewById(R.id.btn_3);
        bt_4 = (Button) findViewById(R.id.btn_4);
        bt_5 = (Button) findViewById(R.id.btn_5);
        bt_6 = (Button) findViewById(R.id.btn_6);
        bt_7 = (Button) findViewById(R.id.btn_7);
        bt_8 = (Button) findViewById(R.id.btn_8);
        bt_9 = (Button) findViewById(R.id.btn_9);
        bt_clear = (Button) findViewById(R.id.btn_clear);
        bt_divide = (Button) findViewById(R.id.btn_divide);
        bt_times = (Button) findViewById(R.id.btn_times);
        bt_delete = (Button) findViewById(R.id.btn_delete);
        bt_add = (Button) findViewById(R.id.btn_add);
        bt_sub = (Button) findViewById(R.id.btn_sub);
        bt_equal = (Button) findViewById(R.id.btn_equal);
        bt_point = (Button) findViewById(R.id.btn_point);
        bt_remainder = (Button) findViewById(R.id.btn_remainder);
        et_input = (EditText) findViewById(R.id.et_input);

        et_input.setKeyListener(null);


        bt_0.setOnClickListener(this);
        bt_1.setOnClickListener(this);
        bt_2.setOnClickListener(this);
        bt_3.setOnClickListener(this);
        bt_4.setOnClickListener(this);
        bt_5.setOnClickListener(this);
        bt_6.setOnClickListener(this);
        bt_7.setOnClickListener(this);
        bt_8.setOnClickListener(this);
        bt_9.setOnClickListener(this);
        bt_add.setOnClickListener(this);
        bt_clear.setOnClickListener(this);
        bt_divide.setOnClickListener(this);
        bt_times.setOnClickListener(this);
        bt_delete.setOnClickListener(this);
        bt_sub.setOnClickListener(this);
        bt_remainder.setOnClickListener(this);
        bt_point.setOnClickListener(this);
        bt_equal.setOnClickListener(this);

    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_caculator);
        initP();
    }

    @Override
    public void onClick(View v) {
        int latest = 0;
        if (fomula.length() != 0) {
            latest = fomula.codePointAt(fomula.length() - 1);
        }
        else
            latest = '.';

        switch (v.getId()) {
            case R.id.btn_0:
                fomula = fomula.append("0");
                et_input.setText(fomula);
                break;
            case R.id.btn_1:
                fomula = fomula.append("1");
                et_input.setText(fomula);
                break;
            case R.id.btn_2:
                fomula = fomula.append("2");
                et_input.setText(fomula);
                break;
            case R.id.btn_3:
                fomula = fomula.append("3");
                et_input.setText(fomula);
                break;
            case R.id.btn_4:
                fomula = fomula.append("4");
                et_input.setText(fomula);
                break;
            case R.id.btn_5:
                fomula = fomula.append("5");
                et_input.setText(fomula);
                break;
            case R.id.btn_6:
                fomula = fomula.append("6");
                et_input.setText(fomula);
                break;
            case R.id.btn_7:
                fomula = fomula.append("7");
                et_input.setText(fomula);
                break;
            case R.id.btn_8:
                fomula = fomula.append("8");
                et_input.setText(fomula);
                break;
            case R.id.btn_9:
                fomula = fomula.append("9");
                et_input.setText(fomula);
                break;
            case R.id.btn_sub:
                if (latest >= '0' && latest <= '9')
                    fomula = fomula.append("-");
                else {
                    if(latest != '.')
                        fomula.delete(fomula.length()-1, fomula.length());
                    fomula = fomula.append("-");
                }
                et_input.setText(fomula);
                break;
            case R.id.btn_add:
                if (latest >= '0' && latest <= '9')
                    fomula = fomula.append("+");
                else {
                    if(latest != '.')
                        fomula.delete(fomula.length()-1, fomula.length());
                    fomula = fomula.append("+");
                }
                et_input.setText(fomula);
                break;
            case R.id.btn_times:
                if (latest >= '0' && latest <= '9')
                    fomula = fomula.append("*");
                else {
                    if(latest != '.')
                        fomula = fomula.delete(fomula.length()-1,fomula.length());
                    fomula = fomula.append("*");
                }
                et_input.setText(fomula);
                break;
            case R.id.btn_divide:
                if (latest >= '0' && latest <= '9')
                    fomula = fomula.append("/");
                else {
                    if(latest != '.')
                     fomula.delete(fomula.length()-1, fomula.length());
                    fomula = fomula.append("/");
                }
                et_input.setText(fomula);
                break;
            case R.id.btn_delete:
                if (fomula.length() > 0)
                    fomula = fomula.delete(fomula.length() - 1, fomula.length());
                et_input.setText(fomula);
                break;
            case R.id.btn_clear:
                fomula = fomula.delete(0, fomula.length());
                et_input.setText(fomula);
                break;
            case R.id.btn_equal:
                String ans="0";
                if(fomula.length()>1){
                    InfixInToDuffix inf = new InfixInToDuffix();
                    try{
                        String a = inf.toSuffix(fomula);
                        System.out.println("out:");
                        System.out.println(a);
                        ans = inf.dealEquation(a);
                        fomula = fomula.delete(0,fomula.length());
                        fomula = fomula.append(ans);
                    }catch (Exception ex){
                        ans = "error";
                        fomula = fomula.delete(0,fomula.length());
                    }
                }
                et_input.setText(ans);
                break;
            case R.id.btn_point:
                fomula = fomula.append(".");
                et_input.setText(fomula);
                break;
            case R.id.btn_remainder:
                if(latest >= '0' && latest <= '9'){
                    fomula.append("%");
                }
                else
                {
                    if(latest != '.')
                        fomula.delete(fomula.length()-1,fomula.length());
                    fomula.append("%");
                }
                et_input.setText(fomula);
                break;
        }
    }
}

声明各个按钮及部件,然后通过findViewById得到对应的对象,然后进行处理相应的处理。

其中有几个细节需要处理,否则会导致程序崩溃:

  • 符号处理。
    • 符号前边不能有符号。
  • 小数点处理。
    • 如果结果是整数,不要加小数点。
    • 小数点的连续使用,如1.2.3.5.1。
  • 运算符号如果出现在数字之前,需要特殊判断。
  • 多个符号连续出现问题。
    • 处理方式为将上一个符号顶替下来,换成最新的运算符。
  • 减号如果作为-负号的情况出现。

3. 运算处理

主要是通过两个栈,将中缀转化为后缀,然后进行求解。其中“*/”运算符的优先级应该与“%”优先级一致,但是这里让“%”优先级低于"*/",然后进行的处理。

package com.example.administrator.calculator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.lang.*;
import java.util.ArrayList;
import java.util.*;
/**
 * Created by pprp on 2018/9/22.
 */

class InfixInToDuffix {
    //使用集合定义好符号的运算优先级别
    private static final Map<Character,Integer>basic =new HashMap<Character, Integer>();
    static {
        basic.put('-',1);
        basic.put('+', 1);
        basic.put('*', 3);
        basic.put('/', 3);
        basic.put('(', 0);
        basic.put('%',2);
    }


    //将中缀表达式转换为后缀表达式
    public String toSuffix(StringBuilder infix){
        List<String> queue = new ArrayList<String>();                                   
        List<Character> stack = new ArrayList<Character>();                            

        char[] charArr = infix.substring(0,infix.length()).trim().toCharArray();                                 
        String standard = "*/+-()%";                                                       
        char ch = '&';                                                                  
        int len = 0;                                                                    
        for (int i = 0; i < charArr.length; i++) {                                      
            ch = charArr[i];                                                            
            if(Character.isDigit(ch)) {                                                  
                len++;
            }else if(ch == '.'){                                                      
                len++;
            }else if(standard.indexOf(ch) != -1) {                                       
                if(len > 0) {                                                           
                    queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len, i)));   
                    len = 0;                                                           
                }
                if(ch == '(') {                                                            
                    stack.add(ch);                                                        
                    continue;                                                          
                }
                if (!stack.isEmpty()) {                                                    
                    int size = stack.size() - 1;                                        
                    boolean flag = false;                                             
                    while (size >= 0 && ch == ')' && stack.get(size) != '(') {            
                        queue.add(String.valueOf(stack.remove(size)));                    
                        size--;                                                        
                        flag = true;                                                  
                    }
                    if(ch==')'&&stack.get(size) == '('){
                        flag = true;
                    }
                    while (size >= 0 && !flag && basic.get(stack.get(size)) >= basic.get(ch)) {   
                        queue.add(String.valueOf(stack.remove(size)));                 
                        size--;
                    }
                }
                if(ch != ')') {                                                      
                    stack.add(ch);                                                 
                } else {                                                          
                    stack.remove(stack.size() - 1);
                }
            }
            if(i == charArr.length - 1) {                                            
                if(len > 0) {                                                     
                    queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len+1, i+1)));
                }
                int size = stack.size() - 1;                                       
                while (size >= 0) {                                                       
                    queue.add(String.valueOf(stack.remove(size)));
                    size--;
                }
            }

        }
        String a = queue.toString();
        return a.substring(1,a.length()-1);
    }


    public String dealEquation(String equation){

        String [] arr = equation.split(", ");
        List<String> list = new ArrayList<String>();


        for (int i = 0; i < arr.length; i++) {             
            int size = list.size();
            switch (arr[i]) {
                case "+": double a = Double.parseDouble(list.remove(size-2))+ Double.parseDouble(list.remove(size-2)); list.add(String.valueOf(a));     break;
                case "-": double b = Double.parseDouble(list.remove(size-2))- Double.parseDouble(list.remove(size-2)); list.add(String.valueOf(b));     break;
                case "*": double c = Double.parseDouble(list.remove(size-2))* Double.parseDouble(list.remove(size-2)); list.add(String.valueOf(c));     break;
                case "/": double d = Double.parseDouble(list.remove(size-2))/ Double.parseDouble(list.remove(size-2)); list.add(String.valueOf(d));       break;
                case "%": double e = Double.parseDouble(list.remove(size-2)) % Double.parseDouble(list.remove(size-2)); list.add(String.valueOf(e));     break;
                default: list.add(arr[i]);     break;                                    //如果是数字  直接放进list中
            }
        }
        return list.size() == 1 ? list.get(0) : "Fail" ;                 
    }
}
posted @ 2018-10-30 07:05  pprp  阅读(3210)  评论(0编辑  收藏  举报