Android 开发笔记___初级控件之实战__计算器
功能简单,实现并不难,对于初学者可以总和了解初级控件的基本使用。
用到的知识点如下:
- 线性布局 LinearLayout:整体界面是从上往下的,因此需要垂直方向的linearlayout;下面每行四个按钮,需要水平的linearlayout。
- 滚动视图 ScrollView :虽然界面不宽也不高,以防万一,有可能会遇到屏幕特别小的手机,因此用一个垂直方向的scrollview。
- 文本视图 TextView :上面标题就是一个textview,结果显示也是textview,但是更高级。能够从下往上滚动,前面的聊天室效果里用到过。
- 按钮 Button :下面的数字、运算符都是按钮。
- 图像视图 ImageView :未用到。
- 图像按钮 ImageButton :由于开根号运算符(√)虽然可以打出来,但是有点不一样,因此需要用到一个图像,就用到了图像按钮。
- 状态列表图形 :都有按下和弹起两种状态,因此订制了按钮的自定义样式。
- 形状图形 :运算结果用到的textview是一个圆角的矩形,所以定义了shape文件,把它作为文本视图的背景。
- 九宫格图片 :最下面的“0”按钮是有点大,因此需要两倍那么大的图片,如果使用普通的图片则会拉宽,效果很不好。因此就用到了。
style
1 <resources> 2 3 <!-- Base application theme. --> 4 <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> 5 <!-- Customize your theme here. --> 6 <item name="colorPrimary">@color/colorPrimary</item> 7 <item name="colorPrimaryDark">@color/colorPrimaryDark</item> 8 <item name="colorAccent">@color/colorAccent</item> 9 </style> 10 <style name="btn_cal"> 11 <item name="android:layout_width">0dp</item> 12 <item name="android:layout_height">match_parent</item> 13 <item name="android:layout_weight">1</item> 14 <item name="android:gravity">center</item> 15 <item name="android:textColor">@color/black</item> 16 <item name="android:textSize">30sp</item> 17 <item name="android:background">@drawable/btn_nine_selector</item> 18 </style> 19 20 </resources>
xml
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 android:layout_width="match_parent" 3 android:layout_height="match_parent" 4 android:padding="5dp" 5 android:gravity="top|center" 6 android:orientation="vertical"> 7 8 <ScrollView 9 android:layout_width="match_parent" 10 android:layout_height="wrap_content"> 11 12 <LinearLayout 13 android:layout_width="match_parent" 14 android:layout_height="wrap_content" 15 android:orientation="vertical"> 16 17 <TextView 18 android:layout_width="match_parent" 19 android:layout_height="wrap_content" 20 android:gravity="center" 21 android:text="简单计算器" 22 android:textColor="#000000" 23 android:textSize="22sp" /> 24 25 <LinearLayout 26 android:layout_width="match_parent" 27 android:layout_height="wrap_content" 28 android:background="@drawable/shape_white_with_stroke" 29 android:orientation="vertical"> 30 31 <TextView 32 android:id="@+id/tv_result" 33 android:layout_width="match_parent" 34 android:layout_height="wrap_content" 35 android:gravity="right|bottom" 36 android:lines="3" 37 android:maxLines="3" 38 android:scrollbars="vertical" 39 android:textColor="#000000" 40 android:textSize="25sp" /> 41 </LinearLayout> 42 43 <LinearLayout 44 android:layout_width="match_parent" 45 android:layout_height="wrap_content" 46 android:orientation="vertical"> 47 48 <LinearLayout 49 android:layout_width="match_parent" 50 android:layout_height="75dp" 51 android:orientation="horizontal"> 52 53 <Button 54 android:id="@+id/btn_cancel" 55 style="@style/btn_cal" 56 android:text="CE" /> 57 58 <Button 59 android:id="@+id/btn_divide" 60 style="@style/btn_cal" 61 android:text="÷" /> 62 63 <Button 64 android:id="@+id/btn_multiply" 65 style="@style/btn_cal" 66 android:text="×" /> 67 68 <Button 69 android:id="@+id/btn_clear" 70 style="@style/btn_cal" 71 android:text="C" /> 72 </LinearLayout> 73 74 <LinearLayout 75 android:layout_width="match_parent" 76 android:layout_height="75dp" 77 android:orientation="horizontal"> 78 79 <Button 80 android:id="@+id/btn_seven" 81 style="@style/btn_cal" 82 android:text="7" /> 83 84 <Button 85 android:id="@+id/btn_eight" 86 style="@style/btn_cal" 87 android:text="8" /> 88 89 <Button 90 android:id="@+id/btn_nine" 91 style="@style/btn_cal" 92 android:text="9" /> 93 94 <Button 95 android:id="@+id/btn_plus" 96 style="@style/btn_cal" 97 android:text="+" /> 98 </LinearLayout> 99 100 <LinearLayout 101 android:layout_width="match_parent" 102 android:layout_height="75dp" 103 android:orientation="horizontal"> 104 105 <Button 106 android:id="@+id/btn_four" 107 style="@style/btn_cal" 108 android:text="4" /> 109 110 <Button 111 android:id="@+id/btn_five" 112 style="@style/btn_cal" 113 android:text="5" /> 114 115 <Button 116 android:id="@+id/btn_six" 117 style="@style/btn_cal" 118 android:text="6" /> 119 120 <Button 121 android:id="@+id/btn_minus" 122 style="@style/btn_cal" 123 android:text="-" /> 124 </LinearLayout> 125 126 <LinearLayout 127 android:layout_width="match_parent" 128 android:layout_height="75dp" 129 android:orientation="horizontal"> 130 131 <Button 132 android:id="@+id/btn_one" 133 style="@style/btn_cal" 134 android:text="1" /> 135 136 <Button 137 android:id="@+id/btn_two" 138 style="@style/btn_cal" 139 android:text="2" /> 140 141 <Button 142 android:id="@+id/btn_three" 143 style="@style/btn_cal" 144 android:text="3" /> 145 146 <ImageButton 147 android:id="@+id/ib_sqrt" 148 android:layout_width="0dp" 149 android:layout_height="match_parent" 150 android:layout_weight="1" 151 android:scaleType="centerInside" 152 android:src="@drawable/sqrt" 153 android:background="@drawable/btn_nine_selector"/> 154 </LinearLayout> 155 156 <LinearLayout 157 android:layout_width="match_parent" 158 android:layout_height="75dp" 159 android:orientation="horizontal"> 160 161 <Button 162 android:id="@+id/btn_zero" 163 style="@style/btn_cal" 164 android:layout_weight="2" 165 android:text="0" /> 166 167 <Button 168 android:id="@+id/btn_dot" 169 style="@style/btn_cal" 170 android:text="." /> 171 172 <Button 173 android:id="@+id/btn_equal" 174 style="@style/btn_cal" 175 android:text="=" /> 176 </LinearLayout> 177 </LinearLayout> 178 </LinearLayout> 179 </ScrollView> 180 181 </LinearLayout>
nineselec0tor
1 <?xml version="1.0" encoding="utf-8"?> 2 <selector xmlns:android="http://schemas.android.com/apk/res/android"> 3 <item android:state_pressed="true" android:drawable="@drawable/button_pressed" /> 4 <item android:drawable="@drawable/button_normal" /> 5 </selector>
putong
1 <?xml version="1.0" encoding="utf-8"?> 2 <selector xmlns:android="http://schemas.android.com/apk/res/android"> 3 <item android:state_pressed="true" android:drawable="@drawable/button_pressed_orig" /> 4 <item android:drawable="@drawable/button_normal_orig" /> 5 </selector>0
shape_oval
1 <?xml version="1.0" encoding="utf-8"?> 2 <shape xmlns:android="http://schemas.android.com/apk/res/android" 3 android:shape="oval" > 4 5 <solid android:color="#ff66aa" /> 6 7 <stroke 8 android:width="1dp" 9 android:color="#ffaaaaaa" /> 10 11 </shape>
rect
1 <?xml version="1.0" encoding="utf-8"?> 2 <shape xmlns:android="http://schemas.android.com/apk/res/android" > 3 4 <solid android:color="#ffdd66" /> 5 6 <stroke 7 android:width="1dp" 8 android:color="#ffaaaaaa" /> 9 10 <corners 11 android:bottomLeftRadius="10dp" 12 android:bottomRightRadius="10dp" 13 android:topLeftRadius="10dp" 14 android:topRightRadius="10dp" /> 15 16 </shape>
white_stroke
1 <?xml version="1.0" encoding="utf-8"?> 2 <shape xmlns:android="http://schemas.android.com/apk/res/android" > 3 4 <solid android:color="#ffffff" /> 5 6 <stroke 7 android:width="1dp" 8 android:color="#bbbbbb" /> 9 10 <corners 11 android:bottomLeftRadius="10dp" 12 android:bottomRightRadius="10dp" 13 android:topLeftRadius="10dp" 14 android:topRightRadius="10dp" /> 15 16 </shape>
main
1 package com.example.alimjan.hello_world; 2 3 import android.app.Activity; 4 import android.content.Context; 5 import android.content.Intent; 6 import android.os.Bundle; 7 import android.support.annotation.Nullable; 8 9 /** 10 * Created by alimjan on 7/1/2017. 11 */ 12 13 import android.support.v7.app.AppCompatActivity; 14 import android.text.method.ScrollingMovementMethod; 15 import android.util.Log; 16 import android.view.View; 17 import android.widget.TextView; 18 import android.widget.Toast; 19 20 import com.example.alimjan.hello_world.Arith; 21 22 23 public class class__2_5 extends AppCompatActivity implements View.OnClickListener { 24 25 private final static String TAG = "CalculatorActivity"; 26 private TextView tv_result; 27 28 @Override 29 protected void onCreate(Bundle savedInstanceState) { 30 super.onCreate(savedInstanceState); 31 setContentView(R.layout.code_2_5); 32 tv_result = (TextView) findViewById(R.id.tv_result); 33 tv_result.setMovementMethod(new ScrollingMovementMethod()); 34 35 findViewById(R.id.btn_cancel).setOnClickListener(this); 36 findViewById(R.id.btn_divide).setOnClickListener(this); 37 findViewById(R.id.btn_multiply).setOnClickListener(this); 38 findViewById(R.id.btn_clear).setOnClickListener(this); 39 findViewById(R.id.btn_seven).setOnClickListener(this); 40 findViewById(R.id.btn_eight).setOnClickListener(this); 41 findViewById(R.id.btn_nine).setOnClickListener(this); 42 findViewById(R.id.btn_plus).setOnClickListener(this); 43 findViewById(R.id.btn_four).setOnClickListener(this); 44 findViewById(R.id.btn_five).setOnClickListener(this); 45 findViewById(R.id.btn_six).setOnClickListener(this); 46 findViewById(R.id.btn_minus).setOnClickListener(this); 47 findViewById(R.id.btn_one).setOnClickListener(this); 48 findViewById(R.id.btn_two).setOnClickListener(this); 49 findViewById(R.id.btn_three).setOnClickListener(this); 50 findViewById(R.id.btn_zero).setOnClickListener(this); 51 findViewById(R.id.btn_dot).setOnClickListener(this); 52 findViewById(R.id.btn_equal).setOnClickListener(this); 53 findViewById(R.id.ib_sqrt).setOnClickListener(this); 54 } 55 56 @Override 57 public void onClick(View v) { 58 int resid = v.getId(); 59 String inputText; 60 if (resid == R.id.ib_sqrt) { 61 inputText = "√"; 62 } else { 63 inputText = ((TextView) v).getText().toString(); 64 } 65 Log.d(TAG, "resid="+resid+",inputText="+inputText); 66 if (resid == R.id.btn_clear) { 67 clear(""); 68 } else if (resid == R.id.btn_cancel) { 69 if (operator.equals("") == true) { 70 if (firstNum.length() == 1) { 71 firstNum = "0"; 72 } else if (firstNum.length() > 0) { 73 firstNum = firstNum.substring(0, firstNum.length() - 1); 74 } else { 75 Toast.makeText(this, "没有可取消的数字了", Toast.LENGTH_SHORT).show(); 76 return; 77 } 78 showText = firstNum; 79 tv_result.setText(showText); 80 } else { 81 if (nextNum.length() == 1) { 82 nextNum = ""; 83 } else if (nextNum.length() > 0) { 84 nextNum = nextNum.substring(0, nextNum.length() - 1); 85 } else { 86 Toast.makeText(this, "没有可取消的数字了", Toast.LENGTH_SHORT).show(); 87 return; 88 } 89 showText = showText.substring(0, showText.length() - 1); 90 tv_result.setText(showText); 91 } 92 } else if (resid == R.id.btn_equal) { 93 if (operator.length() == 0 || operator.equals("=") == true) { 94 Toast.makeText(this, "请输入运算符", Toast.LENGTH_SHORT).show(); 95 return; 96 } else if (nextNum.length() <= 0) { 97 Toast.makeText(this, "请输入数字", Toast.LENGTH_SHORT).show(); 98 return; 99 } 100 if (caculate() == true) { 101 operator = inputText; 102 showText = showText + "=" + result; 103 tv_result.setText(showText); 104 } else { 105 return; 106 } 107 } else if (resid == R.id.btn_plus || resid == R.id.btn_minus 108 || resid == R.id.btn_multiply || resid == R.id.btn_divide ) { 109 if (firstNum.length() <= 0) { 110 Toast.makeText(this, "请输入数字", Toast.LENGTH_SHORT).show(); 111 return; 112 } 113 if (operator.length() == 0 || operator.equals("=") == true 114 || operator.equals("√") == true) { 115 operator = inputText;// 操作符 116 showText = showText + operator; 117 tv_result.setText(showText); 118 } else { 119 Toast.makeText(this, "请输入数字", Toast.LENGTH_SHORT).show(); 120 return; 121 } 122 } else if (resid == R.id.ib_sqrt) { 123 if (firstNum.length() <= 0) { 124 Toast.makeText(this, "请输入数字", Toast.LENGTH_SHORT).show(); 125 return; 126 } 127 if (Double.parseDouble(firstNum) < 0) { 128 Toast.makeText(this, "开根号的数值不能小于0", Toast.LENGTH_SHORT).show(); 129 return; 130 } 131 result = String.valueOf(Math.sqrt(Double.parseDouble(firstNum))); 132 firstNum = result; 133 nextNum = ""; 134 operator = inputText; 135 showText = showText + "√=" + result; 136 tv_result.setText(showText); 137 Log.d(TAG, "result="+result+",firstNum="+firstNum+",operator="+operator); 138 } else { 139 if (operator.equals("=") == true) { 140 operator = ""; 141 firstNum = ""; 142 showText = ""; 143 } 144 if (resid == R.id.btn_dot) { 145 inputText = "."; 146 } 147 if (operator.equals("") == true) { 148 firstNum = firstNum + inputText; 149 } else { 150 nextNum = nextNum + inputText; 151 } 152 showText = showText + inputText; 153 tv_result.setText(showText); 154 } 155 return; 156 } 157 158 private String operator = ""; // 操作符 159 private String firstNum = ""; // 前一个操作数 160 private String nextNum = ""; // 后一个操作数 161 private String result = ""; // 当前的计算结果 162 private String showText = ""; // 显示的文本内容 163 164 // 开始加减乘除四则运算 165 private boolean caculate() { 166 if (operator.equals("+") == true) { 167 result = String.valueOf(Arith.add(firstNum, nextNum)); 168 } else if (operator.equals("-") == true) { 169 result = String.valueOf(Arith.sub(firstNum, nextNum)); 170 } else if (operator.equals("×") == true) { 171 result = String.valueOf(Arith.mul(firstNum, nextNum)); 172 } else if (operator.equals("÷") == true) { 173 if ("0".equals(nextNum)) { 174 Toast.makeText(this, "被除数不能为零", Toast.LENGTH_SHORT).show(); 175 return false; 176 } else { 177 result = String.valueOf(Arith.div(firstNum, nextNum)); 178 } 179 } 180 firstNum = result; 181 nextNum = ""; 182 return true; 183 } 184 185 // 清空并初始化 186 private void clear(String text) { 187 showText = text; 188 tv_result.setText(showText); 189 operator = ""; 190 firstNum = ""; 191 nextNum = ""; 192 result = ""; 193 } 194 195 public static void startHome(Context mContext) { 196 Intent intent = new Intent(mContext, class__2_5.class); 197 mContext.startActivity(intent); 198 } 199 200 }
Arith
1 package com.example.alimjan.hello_world; 2 3 import java.math.BigDecimal; 4 5 public class Arith { 6 // 默认除法运算精度 7 private static final int DEF_DIV_SCALE = 10; 8 9 // 这个类不能实例化 10 private Arith() { 11 ; 12 } 13 14 /** 15 * 提供精确的加法运算。 16 * 17 * @param v1 18 * 被加数 19 * @param v2 20 * 加数 21 * @return 两个参数的和 22 */ 23 public static String add(double v1, double v2) { 24 BigDecimal b1 = new BigDecimal(Double.toString(v1)); 25 BigDecimal b2 = new BigDecimal(Double.toString(v2)); 26 return String.valueOf(b1.add(b2)); 27 } 28 29 /** 30 * 提供精确的加法运算。 31 * 32 * @param v1 33 * 被加数 34 * @param v2 35 * 加数 36 * @return 两个参数的和 37 */ 38 public static String add(String v1, String v2) { 39 BigDecimal b1 = new BigDecimal(v1); 40 BigDecimal b2 = new BigDecimal(v2); 41 return String.valueOf(b1.add(b2)); 42 } 43 44 /** 45 * 提供精确的减法运算。 46 * 47 * @param v1 48 * 被减数 49 * @param v2 50 * 减数 51 * @return 两个参数的差 52 */ 53 public static String sub(double v1, double v2) { 54 BigDecimal b1 = new BigDecimal(Double.toString(v1)); 55 BigDecimal b2 = new BigDecimal(Double.toString(v2)); 56 return String.valueOf(b1.subtract(b2)); 57 } 58 59 /** 60 * 提供精确的减法运算。 61 * 62 * @param v1 63 * 被减数 64 * @param v2 65 * 减数 66 * @return 两个参数的差 67 */ 68 public static String sub(String v1, String v2) { 69 BigDecimal b1 = new BigDecimal(v1); 70 BigDecimal b2 = new BigDecimal(v2); 71 return String.valueOf(b1.subtract(b2)); 72 } 73 74 /** 75 * 提供精确的乘法运算。 76 * 77 * @param v1 78 * 被乘数 79 * @param v2 80 * 乘数 81 * @return 两个参数的积 82 */ 83 public static String mul(double v1, double v2) { 84 BigDecimal b1 = new BigDecimal(Double.toString(v1)); 85 BigDecimal b2 = new BigDecimal(Double.toString(v2)); 86 return String.valueOf(b1.multiply(b2)); 87 } 88 89 /** 90 * 提供精确的乘法运算。 91 * 92 * @param v1 93 * 被乘数 94 * @param v2 95 * 乘数 96 * @return 两个参数的积 97 */ 98 public static String mul(String v1, String v2) { 99 BigDecimal b1 = new BigDecimal(v1); 100 BigDecimal b2 = new BigDecimal(v2); 101 return String.valueOf(b1.multiply(b2)); 102 } 103 104 /** 105 * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到 小数点以后10位,以后的数字四舍五入。 106 * 107 * @param v1 108 * 被除数 109 * @param v2 110 * 除数 111 * @return 两个参数的商 112 */ 113 public static String div(double v1, double v2) { 114 return div(v1, v2, DEF_DIV_SCALE); 115 } 116 117 /** 118 * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到 小数点以后10位,以后的数字四舍五入。 119 * 120 * @param v1 121 * 被除数 122 * @param v2 123 * 除数 124 * @return 两个参数的商 125 */ 126 public static String div(String v1, String v2) { 127 return div(v1, v2, DEF_DIV_SCALE); 128 } 129 130 /** 131 * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 定精度,以后的数字四舍五入。 132 * 133 * @param v1 134 * 被除数 135 * @param v2 136 * 除数 137 * @param scale 138 * 表示表示需要精确到小数点以后几位。 139 * @return 两个参数的商 140 */ 141 public static String div(double v1, double v2, int scale) { 142 if (scale < 0) { 143 throw new IllegalArgumentException( 144 "The scale must be a positive integer or zero"); 145 } 146 BigDecimal b1 = new BigDecimal(Double.toString(v1)); 147 BigDecimal b2 = new BigDecimal(Double.toString(v2)); 148 return String.valueOf(b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP)); 149 } 150 151 /** 152 * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 定精度,以后的数字四舍五入。 153 * 154 * @param v1 155 * 被除数 156 * @param v2 157 * 除数 158 * @param scale 159 * 表示表示需要精确到小数点以后几位。 160 * @return 两个参数的商 161 */ 162 public static String div(String v1, String v2, int scale) { 163 if (scale < 0) { 164 throw new IllegalArgumentException( 165 "The scale must be a positive integer or zero"); 166 } 167 BigDecimal b1 = new BigDecimal(v1); 168 BigDecimal b2 = new BigDecimal(v2); 169 170 BigDecimal result = null; 171 try { 172 result = b1.divide(b2); 173 } catch (Exception e) { 174 result = b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP); 175 } 176 return String.valueOf(result); 177 } 178 179 /** 180 * 提供精确的小数位四舍五入处理。 181 * 182 * @param v 183 * 需要四舍五入的数字 184 * @param scale 185 * 小数点后保留几位 186 * @return 四舍五入后的结果 187 */ 188 public static String round(double v, int scale) { 189 if (scale < 0) { 190 throw new IllegalArgumentException( 191 "The scale must be a positive integer or zero"); 192 } 193 BigDecimal b = new BigDecimal(Double.toString(v)); 194 BigDecimal one = new BigDecimal("1"); 195 return String.valueOf(b.divide(one, scale, BigDecimal.ROUND_HALF_UP)); 196 } 197 198 /** 199 * 提供精确的小数位四舍五入处理。 200 * 201 * @param v 202 * 需要四舍五入的数字 203 * @param scale 204 * 小数点后保留几位 205 * @return 四舍五入后的结果 206 */ 207 public static String round(String v, int String, int scale) { 208 if (scale < 0) { 209 throw new IllegalArgumentException( 210 "The scale must be a positive integer or zero"); 211 } 212 BigDecimal b = new BigDecimal(v); 213 BigDecimal one = new BigDecimal("1"); 214 215 b.divide(one, scale, BigDecimal.ROUND_HALF_UP); 216 217 return null; 218 } 219 }