素晴らしい電卓アプリ
中置操作
infix操作は、数値スタックと記号スタックの2つのスタックを定義します。それぞれ、ユーザーが入力した数値(例:1、2、3)と記号(例:+、-)を格納します。
次のビデオでは1を使用しています。例として+2+ 3/2 * 3%3;最初に1を入力し、次に+を入力し、オペレーターのクリックイベントを監視して、それぞれデジタルスタックとシンボルスタックに配置し、次に2と+を入力します。 +を監視し、シンボルスタックの最上位要素を取り出して、それが初期化要素であるかどうかを判断します。そうでない場合は、デジタルスタックの最上位要素を取り出し、スプライスされた文字を別の算術数として取得します;(デジタルスタックの最上位要素&(シンボルスタックの最上位要素を表す)スプライス文字列)(1 + 2);結果3を取得した後、それを数値スタックにプッシュし、2番目の+記号をシンボルスタックにプッシュします。次の操作;など...
エフェクトビデオ
手術
カスタム円形TextView
レンダリング
attrファイルを作成する
コントロールのジェスチャアクションを監視して、ボタンのスタイルを変更します。つまり、押すと白、離すとオレンジになります。
<resources>
<declare-styleable name="SetCircle">
<attr name="CircleColor" format="color"/>
<attr name="SelectCircle" format="color"/>
</declare-styleable>
</resources>
円を描く
protected void onDraw(Canvas canvas) {
//判断手势动作,改变控件状态
if (isSelect){
CirclePaint.setColor( SelectCircle );
}else {
CirclePaint.setColor( CircleColor );
}
//设置填充方式
CirclePaint.setStyle( Paint.Style.FILL );
//设置抗锯齿
CirclePaint.setAntiAlias( true );
RectF rectF = new RectF();
//设置半径,比较长宽,取最大值
int radius = getMeasuredWidth() > getMeasuredHeight() ? getMeasuredWidth() : getMeasuredHeight();
rectF.set(getPaddingLeft(),getPaddingTop(),radius-getPaddingRight(),radius-getPaddingBottom());
//绘制圆弧
canvas.drawArc(rectF,0,360,false,CirclePaint);
super.onDraw(canvas);
}
キャラクタースプライシング
ユーザーが入力した数字はStringBuilderを介してスプライスされ、リセットボタンはセグメントの最後で判断され、ナンバースタック、シンボルスタック、およびスプライスされた文字列の内容はすべてクリアされます。
private class NumOnClick implements View.OnClickListener{
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.Zero:
numBuilder.append('0');
break;
case R.id.One:
numBuilder.append('1');
break;
case R.id.Two:
numBuilder.append('2');
break;
case R.id.Three:
numBuilder.append('3');
break;
case R.id.Four:
numBuilder.append('4');
break;
case R.id.Five:
numBuilder.append('5');
break;
case R.id.Six:
numBuilder.append('6');
break;
case R.id.Seven:
numBuilder.append('7');
break;
case R.id.Eight:
numBuilder.append('8');
break;
case R.id.Nine:
numBuilder.append('9');
break;
case R.id.Point:
numBuilder.append('.');
break;
case R.id.Reset:
isReset = true;
}
if (isReset){
PopStack();
numBuilder.delete(0,numBuilder.length());
ResultBox.setText("0");
operatorStack.push('#');
isReset = false;
}else {
ResultBox.setText(numBuilder.toString());
}
}
}
空のスタック要素
番号スタックとシンボルスタックの要素を空にします
private void PopStack(){
while (numStack.isEmpty()){
numStack.pop();
}
while (operatorStack.isEmpty()){
operatorStack.pop();
}
}
操作の実行
ジェスチャーモニタリング
ここでは、加算演算子を例として取り上げ、プレスとリリースを監視し、それぞれ制御スタイルを変更し、対応する演算子を渡して操作します。
private class OperatorOnClick implements View.OnTouchListener{
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
boolean isPress = false;
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN){
isPress = true;
}
switch (view.getId()){
case R.id.Add:
if (isPress){
mAdd.IsSelect(true);
mAdd.setTextColor(getResources().getColor(R.color.normal));
StartOperation(ADD);
}else {
mAdd.IsSelect(false);
mAdd.setTextColor(getResources().getColor(R.color.select));
}
break;
プッシュ&&ポップ
初期化中に、シンボルスタックを「#」シンボルにプッシュします。これは最初の実行を意味し、結果操作は実行されません。
operatorStack.push('#');
初めて実行するときは、シンボルスタックの一番上の要素、つまり「#」が取り出されます。1と+が入力された場合、実際には別のオペランドがあるため、この時点では式を作成できません。 、スタックに直接プッシュされ、結果は実行されません。操作;次に、連結された文字列をクリアします。100と+が入力された場合、+記号がユーザーインターフェイスに表示されないため、クリアされない場合、後で入力した文字はその後に追加されます。たとえば、50を入力した場合、つまり10050にクリアしないと、ユーザーエクスペリエンスの低下や使用の煩わしさなどの欠点が発生し
ます。100と+を入力してから、50とを入力すると--100 + 50-式を作成するには、上記の説明に示すように、最初は計算が実行されません。2回目は入力-、つまり、シンボルスタックの最上位要素+を取得し、オペランド100と50、それらをEXEOperation()メソッドに渡して、計算結果を開始します
private void StartOperation(char symbol){
char operator = operatorStack.pop();
if (operator == EQUAL){
operatorStack.push(symbol);
} else if (operator == '#'){
numStack.push(numBuilder.toString().isEmpty()?0:Double.parseDouble(numBuilder.toString()));
operatorStack.push(symbol);
numBuilder.delete(0,numBuilder.length());
}else {
switch (operator){
case ADD:
EXEOperation(numStack.pop(),numBuilder.toString().isEmpty()?0:Double.parseDouble(numBuilder.toString()),ADD);
break;
case SUB:
EXEOperation(numStack.pop(),numBuilder.toString().isEmpty()?0:Double.parseDouble(numBuilder.toString()),SUB);
break;
case MULTIPLY:
EXEOperation(numStack.pop(),numBuilder.toString().isEmpty()?0:Double.parseDouble(numBuilder.toString()),MULTIPLY);
break;
case DIVISION:
EXEOperation(numStack.pop(),numBuilder.toString().isEmpty()?0:Double.parseDouble(numBuilder.toString()),DIVISION);
break;
case MOD:
EXEOperation(numStack.pop(),numBuilder.toString().isEmpty()?0:Double.parseDouble(numBuilder.toString()),MOD);
break;
case EQUAL:
EXEOperation(numStack.pop(),numBuilder.toString().isEmpty()?0:Double.parseDouble(numBuilder.toString()));
break;
}
}
}
運転結果
3つのパラメータは、最初のオペランド、別のオペランド、およびシンボルスタックの最上位要素であり、シンボルが判断され、結果が計算されます。次に、結果がスタックにプッシュされ、2番目の演算子がスタックに一致するようにプッシュされます。
重要なのは、等しいキーを判断することです
。1:たとえば、式1 + 1-を入力し、2番目の演算子を監視して前の結果を取得し、数字と記号を入力して前の結果を取得します...
2:たとえば式1+1 =を入力すると、この時点では、等しいシンボルは監視されず、演算を完了できません。解決策は、等しいシンボルをシンボルスタックにプッシュせず、結果を直接スタックにプッシュすることです。操作を完了するための最初のステップに相当します。
小数点以下の桁数
結果の文字列に対して部分文字列のインターセプトが実行され、小数点以下の桁数があるかどうかが判別されます。これはdouble型であるため、デフォルトでは小数点以下の桁数があります。例:
(1)1.0、小数点以下の0を省略して0を直接出力します。
(2)1.05、小数点以下を省略せずに直接出力します。
//判断小数位之后是否有数字
if (str.substring(str.indexOf('.') + 1, str.length() - 1).isEmpty()) {
str = str.substring(0, str.indexOf('.'));
}
オペコード
private void EXEOperation(double front,double rear,char operator) {
double result = 0;
String str;
/**
* 对连续点击运算符,而运算数字并未符合标准时进行判断
* 例如:12+
* 此时12和+分别进栈,此时若再点击运算符+,则无法进行运算,因为rear运算数为空*/
switch (operator) {
case ADD:
result = front + rear;
break;
case SUB:
result = front - rear;
break;
case MULTIPLY:
result = front * rear;
break;
case DIVISION:
result = front / rear;
break;
case MOD:
result = front < rear ? front :front % rear;
break;
}
numStack.push(result);
if (isReturn){
operatorStack.push(EQUAL);
}else {
operatorStack.push(operator);
isReturn = false;
}
str = String.valueOf(result);
//判断小数位之后是否有数字
if (str.substring(str.indexOf('.') + 1, str.length() - 1).isEmpty()) {
str = str.substring(0, str.indexOf('.'));
}
ResultBox.setText(str);
//前运算符清空,为后运算符输入做准备
numBuilder.delete(0,numBuilder.length());
}
任意のベース変換
10進数を入力して、それぞれ対応する2進数、8進数、16進数に変換します。
エフェクトビデオ
変換ベース
ベース変換
複数の基数を個別に変換する必要があるため、配列の長さを判断できません。つまり、各数値の最初の要素が配列の長さを格納するためのアドレスとして使用されます。
private int[] Conversion(int num,int binary){
int[] remainder = new int[255];
int count = 1;
do {
remainder[count++] = num%binary;
num /= binary;
} while (num != 0);
remainder[0] = count;
return remainder;
}
結果の反転
解析された16進配列を反転することにより、16進10-A、11-B ...であるため、それを判断し、文字列連結を使用して、最後に結果文字列を返す必要があります。
private String Inversion(int[] array){
StringBuilder builder = new StringBuilder();
for (int i = array[0]-1; i >=1 ; i--) {
if (array[i] == 10){
builder.append("A");
}else if (array[i] == 11){
builder.append("B");
}else if (array[i] == 12){
builder.append("C");
}else if (array[i] == 13){
builder.append("D");
}else if (array[i] == 14){
builder.append("E");
}else if (array[i] == 15){
builder.append("F");
}else {
builder.append(array[i]);
}
}
return builder.toString();
}
結果が返されました
int num = Integer.parseInt(ResultBox.getText().toString());
Binary_2.setText(Inversion(Conversion(num,2)));
Binary_8.setText(Inversion(Conversion(num,8)));
Binary_10.setText(Inversion(Conversion(num,10)));
Binary_16.setText(Inversion(Conversion(num,16)));