Android计算器学习
Android Studio 2.3.2 。参考文章:http://blog.csdn.net/like_program/article/details/51813632
1. 新建工程 MyCalculator,一路下一步,均采用默认值。
2. 按照要求修改三个xml文件内容。很多地方工程名字不一样,改成自己的名字。
3. 按照步骤修改Activity_main.XML文件,遇到问题:
android:singleLine="false" 过时
暂时处理方式:删掉此行。
4. 按照步骤依次加入代码,计算器可以正常运行。
5. 原文作者写的注释非常详细,计划认真阅读后,自己做一遍。
6. 未增加美化部分,留作后面的内容学习。http://blog.csdn.net/like_program/article/details/51925765
MainActivity.java
1 package com.example.mycalculator; 2 3 import android.os.Bundle; 4 import android.support.v7.app.AppCompatActivity; 5 import android.text.Html; 6 import android.view.View; 7 import android.view.Window; 8 import android.widget.AdapterView; 9 import android.widget.AdapterView.OnItemClickListener; 10 import android.widget.ArrayAdapter; 11 import android.widget.EditText; 12 import android.widget.GridView; 13 14 import java.util.ArrayList; 15 import java.util.List; 16 17 import cn.skw.calculator.Calculator; 18 19 public class MainActivity extends AppCompatActivity { 20 21 /** 22 * 操作按钮 23 */ 24 private GridView mGridView = null; 25 26 /** 27 * 输入框 28 */ 29 private EditText mEditInput = null; 30 31 /** 32 * 适配器 33 */ 34 private ArrayAdapter mAdapter = null; 35 36 /** 37 * 已计算的表达式 38 */ 39 private String mPreStr = ""; 40 41 /** 42 * 待计算的表达式 43 */ 44 private String mLastStr = ""; 45 46 /** 47 * 计算结果 48 */ 49 private Object mResult = null; 50 51 /** 52 * 判断刚刚是否成功执行完一个表达式 53 * 以为,刚加一个表达式时,需要在原来的表达式后面加上换行标签 54 */ 55 private boolean mIsExecuteNow = false; 56 57 /** 58 * 换行符 59 */ 60 private final String newLine = "<br>"; 61 62 /** 63 * 操作按钮上的字符集合 64 */ 65 private final String[] mTextBtns = new String[]{ 66 "Back","(",")","CE", 67 "7","8","9","/", 68 "4","5","6","*", 69 "1","2","3","+", 70 "0",".","=","-", 71 }; 72 73 /** 74 * 用来存储操作按钮上的字符集合 75 */ 76 private List<String> mTextBtnsList = new ArrayList<String>(); 77 78 @Override 79 protected void onCreate(Bundle savedInstanceState) { 80 super.onCreate(savedInstanceState); 81 // 隐藏标题栏 82 requestWindowFeature(Window.FEATURE_NO_TITLE); 83 setContentView(R.layout.activity_main); 84 85 initTextBtns(); 86 87 mEditInput = (EditText) findViewById(R.id.edit_input); 88 mGridView = (GridView) findViewById(R.id.grid_buttons); 89 // 创建适配器 90 mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mTextBtns); 91 // mAdapter = new CalculatorAdapter(this, R.id.text_button, mTextBtnsList); 92 // 设置适配器 93 mGridView.setAdapter(mAdapter); 94 95 // 禁止EditText从键盘输入 96 mEditInput.setKeyListener(null); 97 // 为操作按钮设置按键监听 98 mGridView.setOnItemClickListener(new OnButtonItemClickListener()); 99 } 100 101 /** 102 * 这个函数用于设置EditText的显示内容,主要是为了加上html标签. 103 * 所有的显示EditText内容都需要调用此函数 104 */ 105 private void setText() { 106 final String[] tags = new String[]{ 107 "<font color='#858585'>", 108 "<font color='#CD2626'>", 109 "</font> " 110 }; 111 StringBuilder builder = new StringBuilder(); 112 // 添加颜色标签 113 builder.append(tags[0]).append(mPreStr).append(tags[2]); 114 builder.append(tags[1]).append(mLastStr).append(tags[2]); 115 // 显示内容 116 mEditInput.setText(Html.fromHtml(builder.toString())); 117 // 设置光标在EditText的最后位置 118 mEditInput.setSelection(mEditInput.getText().length()); 119 } 120 121 /** 122 * 执行 待计算表达式,当用户按下 = 号时,调用这个方法 123 */ 124 private void executeExpression() { 125 try { 126 // 调用第三方jar包来执行运算 127 mResult = Calculator.execute(mLastStr); 128 /** 129 * 将计算得到的结果进行处理, 130 * 若结果的小数点后有4位以上,就只保留4位小数 131 * 否则不做处理 132 */ 133 mResult = covertNumber(mResult); 134 } catch (Exception e) { 135 /** 136 * 如果捕获到异常,表示表达式执行失败, 137 * 这里设置为false是因为并没有执行成功,还不能新的表达式求值 138 */ 139 mIsExecuteNow = false; 140 return; 141 } 142 /** 143 * 若计算结果成功,把 "=" 和 结果 加到待计算表达式, 144 * 更新视图, 145 * 设置标识为true 146 */ 147 mLastStr += "="+ mResult; 148 setText(); 149 mIsExecuteNow = true; 150 } 151 152 /** 153 * 先把计算的结果转换为 float ,再把结果进行四舍五入,然后看能不能被1整除, 154 * 如果能整除,说明结果是个 float 类型的整数,将结果转换为 int 类型返回 155 * 如果不能,说明结果是个小数,直接将结果返回 156 * 157 * @param number 结果 158 * @return 处理后的结果 159 */ 160 private Object covertNumber(Object number) { 161 /** 162 * 将传入的结果先转换为 string 类型,再转换为 float 类型,赋值给 resultFloat 163 * 这里将 result 转换为 float 类型是因为 float 类型参数是有小数点的, 164 * 而结果(number)先假设也是有小数点,这样 resultFloat 可以完全接受结果(number)而不损失精度 165 */ 166 float resultFloat = Float.valueOf(number.toString()); 167 /** 168 * 将 resultFloat 先乘10000,然后调用Math.round()方法,进行四舍五入,再除以10000,就把 resultFloat 四舍五入了 169 */ 170 resultFloat = (float) (Math.round(resultFloat * 10000)) / 10000; 171 if (resultFloat % 1 == 0) { 172 return (int)resultFloat; 173 } else { 174 return resultFloat; 175 } 176 } 177 178 /** 179 * 把字符集合依次添加到List中 180 */ 181 private void initTextBtns() { 182 for (String btn : mTextBtns) { 183 mTextBtnsList.add(btn); 184 } 185 } 186 187 private class OnButtonItemClickListener implements OnItemClickListener { 188 @Override 189 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 190 String text = (String) parent.getAdapter().getItem(position); 191 if (text.equals("=")) { 192 // 执行运算 193 executeExpression(); 194 } else if (text.equals("Back")) { 195 /** 196 * 如果按下退格键,表示删除一个字符 197 * 如果待计算表达式长度为0,则需要把已计算表达式的最后 198 * 部分赋值给待计算表达式 199 * 200 * 例如: 201 * 202 * 已计算表达式:1+1=2 203 * 待计算表达式:空 204 * 205 * 按下Back键后: 206 * 207 * 已计算表达式:空 208 * 待计算表达式:1+1=2 209 * 210 */ 211 if (mLastStr.length() == 0) { 212 /** 213 * 如果已计算表达式的长度不是0,那么此时 214 * 已计算表达式必然以换行符结尾 215 */ 216 if (mPreStr.length() != 0) { 217 // 清除已计算表达式末尾的换行符 218 mPreStr = mPreStr.substring(0, mPreStr.length() - newLine.length()); 219 // 找到前一个换行符的位置 220 int index = mPreStr.lastIndexOf(newLine); 221 if (index == -1) { 222 /** 223 * -1表示没有找到,即 已计算表达式只有一个 224 * 此时把 仅有的一个已计算表达式赋值给待计算表达式 225 * 226 * 例如: 227 * 228 * 已计算表达式:1+1=2 229 * 待计算表达式:空 230 * 231 * 按下Back键后: 232 * 233 * 已计算表达式:空 234 * 待计算表达式:1+1=2 235 */ 236 mLastStr = mPreStr; 237 // 已计算表达式赋值为空 238 mPreStr = ""; 239 } else { 240 /** 241 * 如果找到前一个换行符,即 已计算表达式数量 > 1 242 * 此时把已计算表达式的最后一个表达式赋值给 待计算表达式 243 * 244 * 例如: 245 * 246 * 已计算表达式:1+1=2 247 * 2+2=4 248 * 待计算表达式:空 249 * 250 * 按下Back键后: 251 * 252 * 已计算表达式:1+1=2 253 * 待计算表达式:2+2=4 254 */ 255 mLastStr = mPreStr.substring(index + newLine.length(), mPreStr.length()); 256 mPreStr = mPreStr.substring(0, index + newLine.length()); 257 } 258 mIsExecuteNow = true; 259 } 260 } else { 261 // 如果待计算表达式长度不是0,则直接减掉一个字符 262 mLastStr = mLastStr.substring(0, mLastStr.length() - 1); 263 } 264 // 更新视图 265 setText(); 266 } else if (text.equals("CE")) { 267 /** 268 * 如果按下 清除键,就把 269 * 待计算表达式 和 已计算表达式 全部清空, 270 * 显示内容全部清空, 271 * 并设置标识符为false 272 * 273 * 这里需要注意下, 274 * 待计算表达式 和 已计算表达式 全部清空, 275 * 并不代表显示内容就清空了。同样, 276 * 显示内容清空,也不代表 待计算表达式 和 已计算表达式 全部清空。 277 */ 278 mPreStr = ""; 279 mLastStr = ""; 280 mIsExecuteNow = false; 281 mEditInput.setText(""); 282 } else { 283 // 按下其他键的情况 284 if (mIsExecuteNow) { 285 /** 286 * 如果刚刚成功执行了一个表达式, 287 * 那么需要把 待计算表达式 加到 已计算表达式 后面并添加换行符 288 * 289 * 例如: 290 * 已计算表达式:空 291 * 待计算表达式:1+1=2 292 * 293 * 按下 1 键后: 294 * 295 * 已计算表达式:1+1=2 296 * 待计算表达式:1 297 * 298 */ 299 mPreStr += mLastStr + newLine; 300 // 重置标识为false 301 mIsExecuteNow = false; 302 /** 303 * 如果按下的键是 + - * / 中的任何一个, 304 * 就把刚刚计算完毕的表达式的结果拿过来, 305 * 放在待计算表达式的开头 306 * 307 * 例如: 308 * 已计算表达式:1+1=2 309 * 待计算表达式:空 310 * 311 * 按下 + 键后: 312 * 313 * 已计算表达式:1+1=2 314 * 待计算表达式:2+ 315 */ 316 if (text.equals("+") || text.equals("-") || text.equals("*") || text.equals("/")) { 317 mLastStr = mResult + text; 318 } else { 319 // 设置待计算表达式的第一个字符为当前按钮按下的内容 320 mLastStr = text; 321 } 322 } else { 323 // 否则直接在待计算表达式后面添加内容就好了 324 mLastStr += text; 325 } 326 // 更新视图 327 setText(); 328 } 329 } 330 } 331 }
activity_main.xml
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:tools="http://schemas.android.com/tools" 4 android:layout_width="match_parent" 5 android:layout_height="match_parent" 6 android:orientation="vertical" 7 tools:context="com.example.mycalculator.MainActivity" > 8 9 <!-- 标题 --> 10 <TextView 11 android:layout_width="match_parent" 12 android:layout_height="50dp" 13 android:text="@string/app_name" 14 android:textSize="18sp" 15 android:gravity="center" 16 android:background="@color/colorBlue" /> 17 18 <RelativeLayout 19 android:layout_width="match_parent" 20 android:layout_height="match_parent"> 21 22 <!--操作界面--> 23 <GridView 24 android:id="@+id/grid_buttons" 25 android:layout_width="match_parent" 26 android:layout_height="wrap_content" 27 android:layout_alignParentBottom="true" 28 android:layout_margin="10dip" 29 android:gravity="center" 30 android:horizontalSpacing="10dp" 31 android:numColumns="4" 32 android:verticalSpacing="10dp"></GridView> 33 34 <!-- 显示界面 --> 35 <EditText 36 android:id="@+id/edit_input" 37 android:layout_width="match_parent" 38 android:layout_height="match_parent" 39 android:layout_above="@id/grid_buttons" 40 android:layout_alignParentTop="true" 41 android:gravity="start" 42 android:hint="@string/hint_text" 43 android:padding="10dp" 44 45 android:textSize="22sp" /> 46 47 </RelativeLayout> 48 49 </LinearLayout>
colors.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="colorPrimary">#3F51B5</color> <color name="colorPrimaryDark">#303F9F</color> <color name="colorAccent">#FF4081</color> <color name="colorBlue">#729FFA</color> <color name="colorWhite">#FFFFFF</color> </resources>
strings.xml
<resources> <string name="app_name">计算器</string> <string name="hint_text">输入表达式</string> </resources>
styles.xml
<resources> <!-- Base application theme. --> <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> <!-- Customize your theme here. --> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> </style> </resources>