第7节 横屏界面
很多应用都会根据设备的横竖屏状态,呈现不同的界面。为的是在不同屏幕长宽的情况下,合理的利用屏幕空间,让用户获得体验上的最佳。
这一节,我们将给计算器添加横屏的布局界面。
7.1 修改方案
添加横屏布局的原理很简单,
- 在
res
目录下增加layout-land
目录; - 在此目录下增加一个同样名字为
activity_main.xml
的布局文件; - 将设备横屏时希望的布局效果在
activity_main.xml
中实现; - 重新在设备上运行程序;
- 当设备从竖屏转成横屏时,
onCreate()
函数会被重新调用,setContentView()
函数此时加载的布局文件,就是res\layout-land\activity_main.xml
;
7.2 调整竖屏结构
通过观察我们可以发现横屏界面和竖屏界面在很多地方都是有相似的。图中相同的色块都比较相似,如果能提取出来重复使用就好了。
为了使横竖界面的布局模块能够抽取出来,保持一致。我们首先要对竖屏界面的布局方式作出修改,让它变成像色块分区那样的结构。这里只需要调整键盘区域,修改activity_main.xml
文件,让其布局结构按如下方案修改:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="2">
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:orientation="vertical">
<!--这里将C DEL /按钮和数字键按照上下排列,将原来的TableLayout分成上下两个部分-->
<!--这里是C DEL /按钮区域,还是使用LinearLayout-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
......
</LinearLayout>
<!--这里是数字键盘区域,还是使用TableLayout-->
<TableLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="4">
......
</TableLayout>
......
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
<!--这里放* - + =符号,不用改变-->
......
</LinearLayout>
7.3 用和标签提取公共布局
Android SDK为我们提供了和两种标签,方便开发者在布局文件中重复利用相同的布局。
7.3.1 模块化显示区域
- 在
res\layout
目录下创建display_area.xml
; 将显示区域的布局放到新建的xml文件当中,最外层使用
merge
标签;<?xml version="1.0" encoding="utf-8"?> <merge xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/result_area" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" style="@style/TextAreaStyle" /> <View android:layout_width="match_parent" android:layout_height="5dp" android:background="@color/colorDisplayDivider" /> <TextView android:id="@+id/formula_area" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" style="@style/TextAreaStyle" /> </merge>
替换
res\layout\activity_main.xml
中显示区域的布局为<include>
标签;<include>
标签的layout
属性用来制定要包含的其他布局,这里要使用@layout/
进行引用。<LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:orientation="vertical"> <include layout="@layout/display_area"/> </LinearLayout>
7.3.2 模块化数字按键区域-0~9
和.
- 在
res\layout
目录下创建digital_btn_area.xml
; 将
TableLayout
中的布局放到新建的xml文件当中,最外层使用merge
标签;<?xml version="1.0" encoding="utf-8"?> <merge xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <TableRow android:layout_weight="1"> <Button android:id="@+id/btn_7" android:onClick="onClick" android:layout_weight="1" android:layout_width="0dp" android:layout_height="match_parent" android:text="@string/btn_7" style="@style/DigitalBtnStyle" /> <Button android:id="@+id/btn_8" android:onClick="onClick" android:layout_weight="1" android:layout_width="0dp" android:layout_height="match_parent" android:text="@string/btn_8" style="@style/DigitalBtnStyle" /> <Button android:id="@+id/btn_9" android:onClick="onClick" android:layout_weight="1" android:layout_width="0dp" android:layout_height="match_parent" android:text="@string/btn_9" style="@style/DigitalBtnStyle" /> </TableRow> <TableRow android:layout_weight="1"> <Button android:id="@+id/btn_4" android:onClick="onClick" android:layout_weight="1" android:layout_width="0dp" android:layout_height="match_parent" android:text="@string/btn_4" style="@style/DigitalBtnStyle" /> <Button android:id="@+id/btn_5" android:onClick="onClick" android:layout_weight="1" android:layout_width="0dp" android:layout_height="match_parent" android:text="@string/btn_5" style="@style/DigitalBtnStyle" /> <Button android:id="@+id/btn_6" android:onClick="onClick" android:layout_weight="1" android:layout_width="0dp" android:layout_height="match_parent" android:text="@string/btn_6" style="@style/DigitalBtnStyle" /> </TableRow> <TableRow android:layout_weight="1"> <Button android:id="@+id/btn_1" android:onClick="onClick" android:layout_weight="1" android:layout_width="0dp" android:layout_height="match_parent" android:text="@string/btn_1" style="@style/DigitalBtnStyle" /> <Button android:id="@+id/btn_2" android:onClick="onClick" android:layout_weight="1" android:layout_width="0dp" android:layout_height="match_parent" android:text="@string/btn_2" style="@style/DigitalBtnStyle" /> <Button android:id="@+id/btn_3" android:onClick="onClick" android:layout_weight="1" android:layout_width="0dp" android:layout_height="match_parent" android:text="@string/btn_3" style="@style/DigitalBtnStyle" /> </TableRow> <TableRow android:layout_weight="1"> <Button android:id="@+id/btn_0" android:onClick="onClick" android:layout_weight="2" android:layout_width="0dp" android:layout_height="match_parent" android:text="@string/btn_0" style="@style/DigitalBtnStyle" /> <Button android:id="@+id/btn_dot" android:onClick="onClick" android:layout_weight="1" android:layout_width="0dp" android:layout_height="match_parent" android:text="@string/btn_dot" style="@style/DigitalBtnStyle" /> </TableRow> </merge>
替换
res\layout\activity_main.xml
中的对应区域的布局为<include>
标签;<TableLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="4"> <include layout="@layout/digital_btn_area"/> </TableLayout>
7.3.3 模块化浅色符号按键区域-C
DEL
和/
- 在
res\layout
目录下创建symbol_light_btn_area.xml
; - 将浅色符号区域
LinearLayout
中的布局放到新建的xml文件当中,最外层使用merge
标签; 需要注意的是,这里要把
android:layout_width
和android:layout_height
都设置成match_parent
,为的是在横屏的时候,这部分按钮也可以被平均分配;<?xml version="1.0" encoding="utf-8"?> <merge xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/btn_c" android:onClick="onClick" android:layout_weight="1" android:layout_width="match_parent" android:layout_height="match_parent" android:text="@string/btn_c" style="@style/SymbolLightBtnStyle" /> <Button android:id="@+id/btn_del" android:onClick="onClick" android:layout_weight="1" android:layout_width="match_parent" android:layout_height="match_parent" android:text="@string/btn_del" style="@style/SymbolLightBtnStyle" /> <Button android:id="@+id/btn_div" android:onClick="onClick" android:layout_weight="1" android:layout_width="match_parent" android:layout_height="match_parent" android:text="@string/btn_div" style="@style/SymbolLightBtnStyle" /> </merge>
在
res\layout\activity_main.xml
中的对应区域,使用<include>
标签;<LinearLayout android:layout_weight="1" android:layout_height="0dp" android:layout_width="match_parent"> <include layout="@layout/symbol_light_btn_area"/> </LinearLayout>
7.3.4 模块化深色符号按键区域-*
-
+
和=
- 在
res\layout
目录下创建symbol_dark_btn_area.xml
; 将深色符号区域
LinearLayout
中的布局放到新建的xml文件当中,最外层使用merge
标签;<?xml version="1.0" encoding="utf-8"?> <merge xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/btn_mul" android:onClick="onClick" android:layout_weight="1" android:layout_width="match_parent" android:layout_height="0dp" android:text="@string/btn_mul" style="@style/SymbolDarkBtnStyle" /> <Button android:id="@+id/btn_sub" android:onClick="onClick" android:layout_weight="1" android:layout_width="match_parent" android:layout_height="0dp" android:text="@string/btn_sub" style="@style/SymbolDarkBtnStyle" /> <Button android:id="@+id/btn_add" android:onClick="onClick" android:layout_weight="1" android:layout_width="match_parent" android:layout_height="0dp" android:text="@string/btn_add" style="@style/SymbolDarkBtnStyle" /> <Button android:id="@+id/btn_equ" android:layout_weight="2" android:layout_width="match_parent" android:layout_height="0dp" android:text="@string/btn_equ" android:onClick="onClick" style="@style/SymbolDarkBtnStyle" /> </merge>
在
res\layout\activity_main.xml
中的对应区域,使用<include>
标签;<LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:orientation="vertical"> <include layout="@layout/symbol_dark_btn_area"/> </LinearLayout>
7.4 创建横屏布局
按照横屏的设计创建横屏布局文件。
在
项目浏览框
,找到res目录
,点击右键,选择new
->android resource file
;在对应栏位按照下图填写;
布局方向,选择
landscape
;这样Android Studio就会在在res
目录下增加layout-land
目录;并在此目录下增加一个名字为activity_main.xml
的布局文件;修改新创建的布局文件为,
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.anddle.calculator.MainActivity" android:background="@color/colorAppBG"> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="2" android:orientation="vertical"> <include layout="@layout/display_area"/> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="3"> <TableLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="3"> <include layout="@layout/digital_btn_area"/> </TableLayout> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:orientation="vertical"> <include layout="@layout/symbol_dark_btn_area"/> </LinearLayout> <LinearLayout android:layout_weight="1" android:layout_height="match_parent" android:layout_width="0dp" android:orientation="vertical"> <include layout="@layout/symbol_light_btn_area"/> </LinearLayout> </LinearLayout> </LinearLayout>
重新运行程序到设备上,并选择设备,就会发现计算器的界面会根据设备横竖状态的不同而自己切换了。
7.5 数据保存
虽然计算器的横竖屏会自动切换界面了,但是我们会发现一个问题:当在竖屏界面输入计算表达式以后,旋转设备,表达式区域会被清空。
所以需要我们增加一个功能,让设备旋转的时候,数据不会被清除掉。
7.5.1 开发框架的优势
Activity由Android SDK开发框架提供给我们使用。它帮助我们完成了很多应用界面启动后需要进行的操作。当我们需要在这些操作中添加自己希望的逻辑时,就可以通过继承覆盖这些方法,覆盖时加上自己的代码,例如Activity的:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
protected void onDestroy() {
super.onDestroy();
}
@Override
protected void onResume() {
super.onResume();
}
@Override
protected void onPause() {
super.onPause();
}
@Override
protected void onStart() {
super.onStart();
}
@Override
protected void onStop() {
super.onStop();
}
@Override
protected void onRestart() {
super.onRestart();
}
这也就是使用框架进行开发的优势。
7.5.2 调用时机
在Activity众多的方法当中,onSaveInstanceState()
和onRestoreInstanceState()
提供了一个Activity被系统自动销毁时,进行处理的机会。
Activity一般是在用户点击返回
按钮后被销毁的,但是有的时候也会被操作系统自动销毁,
- 系统资源不足时,操作系统会销毁在后台的Activity(隐藏起来不可见的Activity,虽然可见但是没有和用户做交互的Activity);
- 当系统的属性发生了变化,需要重新创建这个Activity时,设备的横竖屏状态变化,就满足这个条件;
onSaveInstanceState()
会在Activity被切换到后台的时候被调用,我们就应该在这里添加上保存数据的逻辑。
如果Activity被系统自动销毁,而下一次系统又要把这个Activity切换到前台,系统就会自动重新创建这个Activity,此时才会触发onRestoreInstanceState()
被调用,在这个时候,我们就可以添加恢复数据的逻辑了。
7.5.3 保存和取出方式
保存数据时,
- 获取计算表达式和结果的内容;
- 将表达式和结果的内容存放到系统提供的
Bundle
当中;
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
TextView formula = (TextView) findViewById(R.id.formula_area);
String strFormula = formula.getText().toString();
outState.putString("KEY_FORMULA_AREA", strFormula);
TextView result = (TextView) findViewById(R.id.result_area);
String strResult = result.getText().toString();
outState.putString("KEY_RESULT_AREA", strResult);
}
恢复数据时,
- 从系统提供的
Bundle
中,取出之前保存的数据; - 将内容重新设置到计算表达式区域和计算结果区域;
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
TextView formula = (TextView) findViewById(R.id.formula_area);
String strFormula = savedInstanceState.getString("KEY_FORMULA_AREA");
formula.setText(strFormula);
TextView result = (TextView) findViewById(R.id.result_area);
String strResult = savedInstanceState.getString("KEY_RESULT_AREA");
result.setText(strResult);
}
至此,计算器横竖屏旋转时代功能就添加完毕了。
/*******************************************************************/
* 版权声明
* 本教程只在CSDN和安豆网发布,其他网站出现本教程均属侵权。
*另外,我们还推出了Arduino智能硬件相关的教程,您可以在我们的网店跟我学Arduino编程中购买相关硬件。同时也感谢大家对我们这些码农的支持。
*最后再次感谢各位读者对安豆
的支持,谢谢:)
/*******************************************************************/