嘿嘿的计算器开发

超简单易懂的计算器设计 —安卓项目

一、涉及的知识点

1、布局

  设计一个app首先当然是设计它的布局了。在我的计算器中,我的理想是它能根据我们手机的横竖屏切换情况来加载不同的布局,这样我就可以在横竖屏界面中呈现不同的组件,因为横屏比竖屏的界面宽度要大很多,所以可以增加更多的组件,所以我从网上的资源找到如何建立横屏的布局文件。

第一步:

  将项目的状态切换到Android状态(Project也可以,不过操作会多一些步骤,在这里就将Android状态下的操作)。找到app\res\layout文件夹

第二步:

  右击layout文件夹,选择new—>选择resource file,之后会跳出一个设置的窗口,

这里写图片描述

  这里要修改两个地方,第一个是file name 命名为与通用的布局文件名称相同,我的一开始layout里面的文件名称为activity_main,所以我就命名为这个了,第二个地方是qualifiers那里,选择Orientation,布局可以随意。修改好了之后按“>>”这个东西,跳出来另一个窗口,上图:

这里写图片描述

  这里面就把Directory name改为layout_land。点击确定后就创建成功了,回到界面的layout,就会看到多了一个land文件,

这里写图片描述
  打开这个land文件也可以看到我们的横屏界面了。

第三步:

  创建好布局文件后,下一步就是在布局文件中添加组件。添加组件需要用到布局。
  在我的计算器中,竖屏布局中只用到了RelativeLayout,在这个布局中就是各个组件彼此之间都有联系,能够通过在design界面中拖拉组件完成布局(拖拉组件容易导致布局的混乱,有种牵一发而动全身的感觉,所以最好使用布局嵌套,仅用一种布局对修改不是很合适)。
  在横屏布局中我用了LinearLayout中嵌套TableLayout和RelativeLayout布局,这样我的布局就会比较稳定,修改一个组件也不容易造成界面混乱。
  添加组件需要对组件的属性进行设置,其他通用的属性就不提出来了,大概是这样:

<TextView
            android:id="@+id/textView2"
            android:layout_width="match_parent"
            android:layout_height="100dip"
            android:gravity="end|bottom"
            android:textSize="28sp"
            android:hint="@string/TestView_name"
            android:background="@drawable/back_dp"
            android:layout_alignParentTop="true"
            android:layout_alignParentLeft="true"/>
<Button
            android:id="@+id/bt_C"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"
            android:layout_below="@+id/textView2"
            android:layout_marginTop="50dp"
            android:text="@string/bt_C" />

  其中值得一提的是各组件的text属性,他的功能是给这个组件命名,为了各种方便,通常需要将text的内容作为引用来@,如上代码中的button所示,我的命名是引用string文件中的bt_C内容,这样当我们要改动text的值时,只要修改String文件中的赋值便可,有点像c语言中的预定义。具体做法如下:
  找到项目目录下的 res\values\string.xml ;
输入 :
   <string name="bt_C">C</string>
  其中bt_C为组件调用他的代号,两个单书名号中间夹的字符就是组件调用@string/bt_C后得到的text字符串。
  在设置组件高度宽度的时候,也要清楚wrap_content和match_parent的区别,其中wrap_content为包裹文本大小,match_parent为填充整个布局空间,都是设置组件宽度和高度能用上的。
如下图为我的布局展示:
竖屏:
横屏:
  添加好组价后,需要再main函数里面设置变量,在运用如R.id.bt_C的形式将组件与布局中的组件联系起来。如下代码:

    bt0 = (Button) findViewById(R.id.bt_0);
    bt1 = (Button) findViewById(R.id.bt_1);
        bt2 = (Button) findViewById(R.id.bt_2);
        bt3 = (Button) findViewById(R.id.bt_3);
        bt4 = (Button) findViewById(R.id.bt_4);
        bt5 = (Button) findViewById(R.id.bt_5);

第四步:

  接下来就是增加监听器和定义监听事件。监听事件中放的就是逻辑运算的代码。
  重点讲讲思路,思路最关键了。(先说明,我的计算器现在只能做简单的二元运算,功能有待日后增加。)
  首先监听按钮点击事件,点击任意按钮就会输入按钮的text内容,赋给字符串str,其中亮点在于在点击运算符按钮时,赋值给str的是

  str += " " + ((Button) v).getText() + " ";

(这样的好处是在之后判断运算符的位置,提取运算符前后数字的时候,能以空格“ ”作为识别参照,而不是运算符,只要getText得到的字符串中有空格,则一定有运算符,就可以依据这个来确定运算符前后的数字

 if (str.contains("+") || str.contains("-") || str.contains("×") || str.contains("÷")) {
   param1 = str.substring(0, str.indexOf(" "));  //第一个空格  //获取第一个因数
   op = str.substring(str.indexOf(" ") + 1, str.indexOf(" ") + 2);  //获取运算符
   param2 = str.substring(str.indexOf(" ") + 3);             //获取第二个因数
            }

)
接着监听等号按钮,一旦按钮被点击,就进行运算。
  其中不断用到字符串转为double型: Double.parseDouble(param1)
double型又转为字符串型的方法: double+"";
判断字符串中出现的第一个字符的位置:str.indexOf(" ")
从某一位置开始赋值给另一个字符串:param2 = str.substring(str.indexOf(" ") + 3);

详细代码可以见链接:
https://github.com/17wwshe/Calculator2.git

二、开发过程中遇到的问题及解决方案

1、横竖屏切换问题:

  设置了activity_main.xml(land)文件并且完成了布局设置之后,我就在mainActivity中设置了监听事件,并初始化所有的组件(在一个方法中将全部组件初始化),并在onCreate中调用初始化组件的方法invit();
  出现问题:
  横竖屏切换不能成功,当由横屏切换成竖屏时,Activity会stop,当屏幕一开始就为竖屏时,直接就退出了。
  后来参考网上的解决方案,在ActivityManifest.xml中的activity中增加一项:

 android:screenOrientation="sensor">

  这一项的意思就是根据感受器来感受你的横竖屏情况,若是横屏就加载横屏布局,竖屏则加载竖屏布局。修改后继续在虚拟机上运行,但是。。。还是没有解决问题。又看到了网上教程介绍,还是在ActivityManifest.xml的activity中增加 :android:configChanges="keyboardHidden|orientation|screenSize"
增加后运行,还是。。。自动退出了。
  后来发现android:configChanges="keyboardHidden|orientation|screenSize"这个代码是令横竖屏切换时不重新onCreat,但是我的简单运算现在不用实现这个功能,所以我又把这行代码删了,保留android:screenOrientation="sensor">
接着我去了解切换横竖屏的生命周期变化,发现是这样:切换时:onPause-> onStop-> onDestory-> onCreate->onStart->onResume 他会重新Creat,所以我的组件初始化要写在onCreate里面,(这里我是想重新初始化的,如果不想重新初始化变量,想保存信息的话,这里的操作就不适合了
  在观察logcat日志的时候,发现他的错误提示为nullPoint,也就是出现了空指针。我返回去查找自己的代码,发现里面有两处地方会导致空指针的出现:
  第一处是我的EditText变量调用了setKeyListener(null)方法,我一开始是想通过这个方法来实现EditText的不可编辑。
  第二处是我的init(),我在初始化组件的时候,是一次性全部初始化的,我的横屏布局比竖屏布局会多一些组件,所以当我为竖屏状态时,我还去初始化了横屏的组件,这也可能造成空指针,且占用了内存。

  所以我的解决方案是对这两处地方都进行改正。
  想设置文本框不可编辑,就将文本框的类型设为TextView,TextView是EditText的父类型,两者的区别是TextView是不可编辑的,就是不能从键盘输入,这不就满足我的要求了吗,EditText是可编辑的,如果用EditText还得多一步设置他不可编辑,不如直接用TextView来创建文本框。
  我把初始化组件的方法分成两个,一个是横竖屏通用的,存放他们共有的组件的初始化,另一个是横屏专用的,因为横屏会比竖屏多些组件,设置监听器的方法也一样,不过具体的监听事件的方法还是用同一个,因为里面可以有switch判断,不会重复。这时只要在onCreate中加上判断现在横竖屏的状态,然后调用相应的方法即可。如下代码:

       int Orientation;
        Orientation = getResources().getConfiguration().orientation;
        Log.d("----", "" + Orientation);
        int mCurrentOrientation = getResources().getConfiguration().orientation;
        if (mCurrentOrientation == Configuration.ORIENTATION_PORTRAIT) {
            // If current screen is portrait
            Log.i("info", "portrait"); // 竖屏日志
            initView_por();
            initEvent_por();  //初始化竖屏组件 
            } 
            else if (mCurrentOrientation == Configuration.ORIENTATION_LANDSCAPE) {
            //If current screen is landscape
            Log.i("info", "landscape"); // 横屏日志
            initView_por();
            initView_land();
            initEvent_por();  //初始化竖屏组件
            initEvent_land();  //初始化横屏组件
        }
        //利用log视察横竖屏状态,并初始化组件
        //横竖屏组件个数不一样,不用同一个方法,避免空指针

  这样在运行一遍就成功了!!!

2、初始化组件问题

  初始化组件最好放在onCreate方法中,这样才能实现初始化,点击事件才能有反应;我之前在调试的时候,把初始化放在了别的方法中,运行之后能够有横竖屏切换,但是点击按钮,text不会显示文本,这就证明我的组件并没有初始化,没有初始化组件(当时我是把所有组件一起初始化的),但能显示横竖屏切换,这就证明了之前切换竖屏就停止运行是因为我的组件一次性初始化,在竖屏的时候造成了空指针,竖屏layout中并没有这些组件,所以导致空指针。

三、完成项目过程中的收获和感想

  完成项目的收获很多,感想也很多。但是这个项目还没完成,因为很容易崩溃,还有不能实现混合运算,没有设置异常处理,所以还需要改进。
  一开始做这个项目的时候,首先要设计项目的功能和界面,我很庆幸自己当时有要弄横竖屏切换的想法,虽然在切换的时候遇到了很多问题,一直卡在切换那里,花了很多时间,网上也的解决方法也很零散,因为遇到的情况都不一样,解决方法也就有点不同,但是能够找到它的原理,找到原理之后,再结合自己的情况思考是哪里出了问题,这样的修改才能真正解决自己的问题,反而不要直接把其他人的解决方案放在自己身上,但可以借鉴。网上的解决方案也是别人的心血,挺佩服他们能想这么多,有他们引导,也挺容易找到自己问题的所在。
  在解决横竖屏切换的问题时,我了解到了横竖屏切换Activity周期的改变情况,也知道了getResources().getConfiguration().orientation方法能够返回横竖屏的状态,借这个方法用在onCreate那里可以帮助判断以决定初始化组件。
  在解决运算的时候,学习到了一种方法,就是在点击运算符按钮的时候,setText的是 str += " " + ((Button) v).getText() + " ";这样只要识别到空格就可以知道有运算符了,也方便运算符及前后数字的提取。很机智的方法。
  这个项目中我还需要对异常类进行处理,让项目不要轻易崩溃。

再次附上我github上的代码仓库:

https://github.com/17wwshe/Calculator2.git

猜你喜欢

转载自blog.csdn.net/weixin_41625927/article/details/80664910