Đầu tiên hãy xem tổng quan giao diện mà chúng ta sẽ cùng nhau thiết kế. Các bộ phận được đánh số để bạn có thể dễ dàng quan sát cũng như màu sắc để nhận diện
Từng khu vực:
1. Hiển thị toàn bộ các số người dùng đã nhập trước đó và đang chờ tính toán cho đến khi người nhập nhấp vào nút C để xóa
2. Khi người dùng nhập số, kết quả của bộ đệm sẽ được hiển thị
3. Giá trị bộ nhớ đệm sẽ được hiển thị ở vùng này
4. Nút tổ chức bộ nhớ đệm
5. Các nút khác
6. Nút để kích hoạt và hiển thị kết quả
7. Nút tính toán + - * /
8. Phím số
9. Trở về
Các trường hợp sử dụng TouchCalculator
Máy tính của chúng ta hỗ trợ các trường hợp sử dụng sau đây:
Máy tính được khởi tạo với giá trị đầu vào từ 0 và ngay sau khi người dùng bắt đầu nhấn nút bàn phím số.
Người dùng sẽ bấm nút bàn phím số và chúng ta sẽ nối thêm mỗi giá trị số đến giá trị hiện tại khu vực # 2
Nếu người dùng nhấn nút dấu phân cách số thập phân được đặt ở Khu vực 5, chúng tôi sẽ nối thêm các dấu phân cách giá trị hiện tại của khu vực # 2
Khi người dùng nhấn một nút toán tử số học được đặt trong Khu vực 7, chúng tôi sẽ hiển thị nội dung bộ đệm đầu vào trong khu vực # 1. Nếu đầu vào bộ đệm có đầu vào, đủ để tính toán một kết quả, chúng ta cũng phải tính toán kết quả và hiển thị các giá trị trong khu vực # 2
Khi người dùng nhấn (=) nút và nếu đầu vào bộ đệm có đầu vào, đủ để sản xuất một kết quả, chúng ta sẽ tính toán kết quả và hiển thị nó trong khu vực # 2, không phải làm gì.
Khi người dùng nhấn nút Backspace (<-), chúng ta sẽ cắt các chữ số cuối cùng của giá trị được hiển thị trong khu vực # 2
Khi người dùng nhấn nút CE, chúng ta sẽ thiết lập lại giá trị hiển thị trong khu vực # 2 để nó trở thành 0
Khi người dùng nhấn nút C, chúng ta sẽ thiết lập lại bộ đệm đầu vào và giá trị hiển thị trong khu vực # 2 để nó trở thành 0
Khi ép người sử dụng (±), chúng tôi sẽ chuyển đổi các dấu hiệu của giá trị đầu vào người sử dụng hiển thị trong khu vực # 2
Khi người dùng nhấn nút MC, chúng ta phải giải phóng bộ nhớ đệm
Khi người dùng nhấn nút MR, chúng ta sẽ đọc các giá trị trong bộ nhớ đệm và hiển thị giá trị đó trong khu vực # 2
Khi người dùng nhấn nút MS, chúng ta sẽ thiết lập giá trị của bộ nhớ đệm để các giá trị hiển thị trong khu vực # 2
Khi người dùng nhấn nút M+ M-, chúng ta sẽ thêm / trừ đi giá trị hiển thị trong khu vực # 2 với giá trị hiện có của bộ nhớ đệm
Khi người dùng nhấn nút SQRT, chúng ta phải tính căn bậc hai của giá trị được hiển thị trong khu vực # 2 và hiển thị kết quả trong khu vực # 2
Khi người dùng nhấn nút 1 / x, chúng ta sẽ tính toán đối ứng của giá trị được hiển thị trong khu vực # 2 và hiển thị kết quả trong khu vực #
Khi người dùng nhấn nút %, chúng ta sẽ tính toán kết quả của bộ đệm đầu vào và tìm thấy các phần trăm kết quả và hiển thị trong khu vực # 2
Tạo giao diện sử dụng main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:id="@+id/txtStack"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="15sp"
android:gravity="right"
android:layout_marginTop = "3sp"
android:layout_marginLeft = "5sp"
android:layout_marginRight = "5sp"/>
<TextView
android:id="@+id/txtInput"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="25sp"
android:gravity="right"
android:layout_marginLeft = "5sp"
android:layout_marginRight = "5sp"/>
<TextView
android:id="@+id/txtMemory"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="15sp"
android:gravity="left"
android:layout_marginLeft = "5sp"
android:layout_marginRight = "5sp"/>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/grdButtons"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:columnWidth="90dp"
android:numColumns="5"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp"
android:stretchMode="columnWidth"
android:gravity="center"/>
</LinearLayout>
Tạo nút bằng cách. Chuột phải layout>New Enum>
KeypadButton.java
package by.QuangIT;
public enum KeypadButton {
MC("MC",KeypadButtonCategory.MEMORYBUFFER)
, MR("MR",KeypadButtonCategory.MEMORYBUFFER)
, MS("MS",KeypadButtonCategory.MEMORYBUFFER)
, M_ADD("M+",KeypadButtonCategory.MEMORYBUFFER)
, M_REMOVE("M-",KeypadButtonCategory.MEMORYBUFFER)
, BACKSPACE("<-",KeypadButtonCategory.CLEAR)
, CE("CE",KeypadButtonCategory.CLEAR)
, C("C",KeypadButtonCategory.CLEAR)
, ZERO("0",KeypadButtonCategory.NUMBER)
, ONE("1",KeypadButtonCategory.NUMBER)
, TWO("2",KeypadButtonCategory.NUMBER)
, THREE("3",KeypadButtonCategory.NUMBER)
, FOUR("4",KeypadButtonCategory.NUMBER)
, FIVE("5",KeypadButtonCategory.NUMBER)
, SIX("6",KeypadButtonCategory.NUMBER)
, SEVEN("7",KeypadButtonCategory.NUMBER)
, EIGHT("8",KeypadButtonCategory.NUMBER)
, NINE("9",KeypadButtonCategory.NUMBER)
, PLUS(" + ",KeypadButtonCategory.OPERATOR)
, MINUS(" - ",KeypadButtonCategory.OPERATOR)
, MULTIPLY(" * ",KeypadButtonCategory.OPERATOR)
, DIV(" / ",KeypadButtonCategory.OPERATOR)
, RECIPROC("1/x",KeypadButtonCategory.OTHER)
, DECIMAL_SEP(",",KeypadButtonCategory.OTHER)
, SIGN("±",KeypadButtonCategory.OTHER)
, SQRT("SQRT",KeypadButtonCategory.OTHER)
, PERCENT("%",KeypadButtonCategory.OTHER)
, CALCULATE("=",KeypadButtonCategory.RESULT)
, DUMMY("",KeypadButtonCategory.DUMMY);
CharSequence mText; // Display Text
KeypadButtonCategory mCategory;
KeypadButton(CharSequence text,KeypadButtonCategory category) {
mText = text;
mCategory = category;
}
public CharSequence getText() {
return mText;
}
}
KeypadButtonCategory.java
package by.QuangIT;
public enum KeypadButtonCategory {
MEMORYBUFFER
, NUMBER
, OPERATOR
, DUMMY
, CLEAR
, RESULT
, OTHER
}
Tạo các nút trên bàn phím:
package by.QuangIT;
import android.content.Context;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
public class KeypadAdapter extends BaseAdapter {
private Context mContext;
// Declare button click listener variable
private OnClickListener mOnButtonClick;
public KeypadAdapter(Context c) {
mContext = c;
}
// Method to set button click listener variable
public void setOnButtonClickListener(OnClickListener listener) {
mOnButtonClick = listener;
}
public int getCount() {
return mButtons.length;
}
public Object getItem(int position) {
return mButtons[position];
}
public long getItemId(int position) {
return 0;
}
// create a new ButtonView for each item referenced by the Adapter
// create a new ButtonView for each item referenced by the Adapter
public View getView(int position, View convertView, ViewGroup parent) {
Button btn;
if (convertView == null) { // if it's not recycled, initialize some attributes
btn = new Button(mContext);
KeypadButton keypadButton = mButtons[position];
if (keypadButton != KeypadButton.DUMMY)
btn.setOnClickListener(mOnButtonClick);
//if(keypadButton != KeypadButton.CLEAR)
// btn.setBackgroundResource(R.drawable.keypadclear1);
// Set CalculatorButton enumeration as tag of the button so that we
// will use this information from our main view to identify what to do
btn.setTag(keypadButton);
} else {
btn = (Button) convertView;
}
btn.setText(mButtons[position].getText());
return btn;
}
// Create and populate keypad buttons array with CalculatorButton enum
// values
private KeypadButton[] mButtons = { KeypadButton.MC, KeypadButton.MR,
KeypadButton.MS, KeypadButton.M_ADD, KeypadButton.M_REMOVE,
KeypadButton.BACKSPACE, KeypadButton.CE, KeypadButton.C,
KeypadButton.SIGN, KeypadButton.SQRT, KeypadButton.SEVEN,
KeypadButton.EIGHT, KeypadButton.NINE, KeypadButton.DIV,
KeypadButton.PERCENT, KeypadButton.FOUR, KeypadButton.FIVE,
KeypadButton.SIX, KeypadButton.MULTIPLY, KeypadButton.RECIPROC,
KeypadButton.ONE, KeypadButton.TWO, KeypadButton.THREE,
KeypadButton.MINUS, KeypadButton.DECIMAL_SEP, KeypadButton.DUMMY,
KeypadButton.ZERO, KeypadButton.DUMMY, KeypadButton.PLUS,
KeypadButton.CALCULATE };
}
Hiển thị bàn phím:
CaculatorProActivity.java
package by.QuangIT;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Iterator;
import java.util.Stack;
import android.app.Activity;
import android.os.Bundle;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.GridView;
import android.view.View;
import android.view.View.OnClickListener;
public class CaculatorProActivity extends Activity {
GridView mKeypadGrid;
TextView userInputText;
TextView memoryStatText;
Stack<String> mInputStack;
Stack<String> mOperationStack;
KeypadAdapter mKeypadAdapter;
TextView mStackText;
boolean resetInput = false;
boolean hasFinalResult = false;
String mDecimalSeperator;
double memoryValue = Double.NaN;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DecimalFormat currencyFormatter = (DecimalFormat) NumberFormat
.getInstance();
char decimalSeperator = currencyFormatter.getDecimalFormatSymbols()
.getDecimalSeparator();
mDecimalSeperator = Character.toString(decimalSeperator);
setContentView(R.layout.main);
// Create the stack
mInputStack = new Stack<String>();
mOperationStack = new Stack<String>();
// Get reference to the keypad button GridView
mKeypadGrid = (GridView) findViewById(R.id.grdButtons);
// Get reference to the user input TextView
userInputText = (TextView) findViewById(R.id.txtInput);
userInputText.setText("0");
memoryStatText = (TextView) findViewById(R.id.txtMemory);
memoryStatText.setText("");
mStackText = (TextView) findViewById(R.id.txtStack);
// Create Keypad Adapter
mKeypadAdapter = new KeypadAdapter(this);
// Set adapter of the keypad grid
mKeypadGrid.setAdapter(mKeypadAdapter);
// Set button click listener of the keypad adapter
mKeypadAdapter.setOnButtonClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Button btn = (Button) v;
// Get the KeypadButton value which is used to identify the
// keypad button from the Button's tag
KeypadButton keypadButton = (KeypadButton) btn.getTag();
// Process keypad button
ProcessKeypadInput(keypadButton);
}
});
mKeypadGrid.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v,
int position, long id) {
}
});
}
private void ProcessKeypadInput(KeypadButton keypadButton) {
//Toast.makeText(this, keypadButton.getText(), Toast.LENGTH_SHORT).show();
String text = keypadButton.getText().toString();
String currentInput = userInputText.getText().toString();
int currentInputLen = currentInput.length();
String evalResult = null;
double userInputValue = Double.NaN;
switch (keypadButton) {
case BACKSPACE: // Handle backspace
// If has operand skip backspace
if (resetInput)
return;
int endIndex = currentInputLen - 1;
// There is one character at input so reset input to 0
if (endIndex < 1) {
userInputText.setText("0");
}
// Trim last character of the input text
else {
userInputText.setText(currentInput.subSequence(0, endIndex));
}
break;
case SIGN: // Handle -/+ sign
// input has text and is different than initial value 0
if (currentInputLen > 0 && currentInput != "0") {
// Already has (-) sign. Remove that sign
if (currentInput.charAt(0) == '-') {
userInputText.setText(currentInput.subSequence(1,
currentInputLen));
}
// Prepend (-) sign
else {
userInputText.setText("-" + currentInput.toString());
}
}
break;
case CE: // Handle clear input
userInputText.setText("0");
break;
case C: // Handle clear input and stack
userInputText.setText("0");
clearStacks();
break;
case DECIMAL_SEP: // Handle decimal seperator
if (hasFinalResult || resetInput) {
userInputText.setText("0" + mDecimalSeperator);
hasFinalResult = false;
resetInput = false;
} else if (currentInput.contains("."))
return;
else
userInputText.append(mDecimalSeperator);
break;
case DIV:
case PLUS:
case MINUS:
case MULTIPLY:
if (resetInput) {
mInputStack.pop();
mOperationStack.pop();
} else {
if (currentInput.charAt(0) == '-') {
mInputStack.add("(" + currentInput + ")");
} else {
mInputStack.add(currentInput);
}
mOperationStack.add(currentInput);
}
mInputStack.add(text);
mOperationStack.add(text);
dumpInputStack();
evalResult = evaluateResult(false);
if (evalResult != null)
userInputText.setText(evalResult);
resetInput = true;
break;
case CALCULATE:
if (mOperationStack.size() == 0)
break;
mOperationStack.add(currentInput);
evalResult = evaluateResult(true);
if (evalResult != null) {
clearStacks();
userInputText.setText(evalResult);
resetInput = false;
hasFinalResult = true;
}
break;
case M_ADD: // Add user input value to memory buffer
userInputValue = tryParseUserInput();
if (Double.isNaN(userInputValue))
return;
if (Double.isNaN(memoryValue))
memoryValue = 0;
memoryValue += userInputValue;
displayMemoryStat();
hasFinalResult = true;
break;
case M_REMOVE: // Subtract user input value to memory buffer
userInputValue = tryParseUserInput();
if (Double.isNaN(userInputValue))
return;
if (Double.isNaN(memoryValue))
memoryValue = 0;
memoryValue -= userInputValue;
displayMemoryStat();
hasFinalResult = true;
break;
case MC: // Reset memory buffer to 0
memoryValue = Double.NaN;
displayMemoryStat();
break;
case MR: // Read memoryBuffer value
if (Double.isNaN(memoryValue))
return;
userInputText.setText(doubleToString(memoryValue));
displayMemoryStat();
break;
case MS: // Set memoryBuffer value to user input
userInputValue = tryParseUserInput();
if (Double.isNaN(userInputValue))
return;
memoryValue = userInputValue;
displayMemoryStat();
hasFinalResult = true;
break;
default:
if (Character.isDigit(text.charAt(0))) {
if (currentInput.equals("0") || resetInput || hasFinalResult) {
userInputText.setText(text);
resetInput = false;
hasFinalResult = false;
} else {
userInputText.append(text);
resetInput = false;
}
}
break;
}
}
private void clearStacks() {
mInputStack.clear();
mOperationStack.clear();
mStackText.setText("");
}
private void dumpInputStack() {
Iterator<String> it = mInputStack.iterator();
StringBuilder sb = new StringBuilder();
while (it.hasNext()) {
CharSequence iValue = it.next();
sb.append(iValue);
}
mStackText.setText(sb.toString());
}
private String evaluateResult(boolean requestedByUser) {
if ((!requestedByUser && mOperationStack.size() != 4)
|| (requestedByUser && mOperationStack.size() != 3))
return null;
String left = mOperationStack.get(0);
String operator = mOperationStack.get(1);
String right = mOperationStack.get(2);
String tmp = null;
if (!requestedByUser)
tmp = mOperationStack.get(3);
double leftVal = Double.parseDouble(left.toString());
double rightVal = Double.parseDouble(right.toString());
double result = Double.NaN;
if (operator.equals(KeypadButton.DIV.getText())) {
result = leftVal / rightVal;
} else if (operator.equals(KeypadButton.MULTIPLY.getText())) {
result = leftVal * rightVal;
} else if (operator.equals(KeypadButton.PLUS.getText())) {
result = leftVal + rightVal;
} else if (operator.equals(KeypadButton.MINUS.getText())) {
result = leftVal - rightVal;
}
String resultStr = doubleToString(result);
if (resultStr == null)
return null;
mOperationStack.clear();
if (!requestedByUser) {
mOperationStack.add(resultStr);
mOperationStack.add(tmp);
}
return resultStr;
}
private String doubleToString(double value) {
if (Double.isNaN(value))
return null;
long longVal = (long) value;
if (longVal == value)
return Long.toString(longVal);
else
return Double.toString(value);
}
private double tryParseUserInput() {
String inputStr = userInputText.getText().toString();
double result = Double.NaN;
try {
result = Double.parseDouble(inputStr);
} catch (NumberFormatException nfe) {
}
return result;
}
private void displayMemoryStat() {
if (Double.isNaN(memoryValue)) {
memoryStatText.setText("");
} else {
memoryStatText.setText("M = " + doubleToString(memoryValue));
}
}
}