前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android开发笔记(七十四)布局文件优化

Android开发笔记(七十四)布局文件优化

作者头像
aqi00
发布2019-01-18 13:01:32
1.2K0
发布2019-01-18 13:01:32
举报
文章被收录于专栏:老欧说安卓老欧说安卓

include/merge

布局优化中常常用到include/merge标签,include的含义类似C代码中的include,意思是直接把指定布局片段包含进当前的布局文件。include适用于多个布局文件中存在相同的xml片段,比如说相同的标题栏、相同的广告栏、相同的进度栏等等。 include的用法很简单,只有下面一句话:

代码语言:javascript
复制
<include layout="@layout/common_title" />

这时必定有个common_title.xml的布局文件,它用于在各页面展示相同的标题区域。 include子布局文件的根节点可以是LinearLayout或RelativeLayout或FrameLayout,可是上级布局文件往往已经有了相同的视图节点,这时子布局的根节点就变成冗余的了,但是布局文件又必须有根节点,着实矛盾。不要急,merge标签便是处理这个问题的,merge要和include配合使用,也就是说,merge只能是include子布局文件的根节点,且merge无需设置额外的属性。merge标签代替了根节点LinearLayout、RelativeLayout和FrameLayout原来的位置,只是告诉编译器:我是个占位的合并标签,不需要对我做布局处理;这样app在渲染UI时,只是简单合并merge标签下的内容,但不做布局计算和调整,从而提高了UI的加载效率。

ViewStub

在一个页面上根据不同条件展示不同的控件,我们常常会设置控件的可视属性,比如调用指定控件的setVisibility方法,若需展示则设置View.VISIBLE,若需隐藏则设置View.GONE。不过gone的控件只是看不到罢了,实际UI渲染时还是会被加载。要想事先不加载,在条件符合时才加载,就得用到标签ViewStub。 ViewStub类似一个简单的View,但具体布局由属性layout指定,并且在app加载UI时,ViewStub不显示界面内容,只有在代码中调用该控件的inflate方法,layout指定的布局才会展示。基于以上特性,ViewStub在提高布局性能上有几个特点: 优点:ViewStub在加载时只占用大约一个View控件的内存,不占用layout整个布局需要的内存; 缺点:ViewStub一旦调用inflate方法,页面内容就显示出来,之后就没有对应的方法再缩回去。如果还想再次隐藏或显示布局,只能通过setVisibility来实现。 举个ViewStub实际运用的场景,手机屏幕在竖屏和横屏切换时,有时希望显示不同的布局,比如竖屏显示列表,横屏则显示网格,横竖屏的截图如下: 竖屏的列表方式界面截图

横屏的网格方式界面截图

下面是具体实现的布局文件:

代码语言:javascript
复制
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="5dp" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:background="#aaaaff"
        android:paddingLeft="10dp"
        android:paddingRight="10dp" >

        <include layout="@layout/common_title" />
    </RelativeLayout>

    <ViewStub
        android:id="@+id/vs_list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout="@layout/viewstub_list" />

    <ViewStub
        android:id="@+id/vs_grid"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout="@layout/viewstub_grid" />

</LinearLayout>

下面是具体实现的代码示例:

代码语言:javascript
复制
import com.example.exmlayout.adapter.ContentGridAdapter;
import com.example.exmlayout.adapter.TitleListAdapter;

import android.app.Activity;
import android.content.res.Configuration;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewStub;
import android.widget.GridView;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.TextView;

public class PlanetActivity extends Activity implements OnClickListener {

	private static final String TAG = "PlanetActivity";
	private String[] mStrList = {"水星", "金星", "地球", "火星", "木星", "土星"
			, "天王星", "海王星", "冥王星"};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_planet);

		ImageButton ib_back = (ImageButton) findViewById(R.id.ib_back);
		ib_back.setOnClickListener(this);
		TextView tv_title = (TextView) findViewById(R.id.tv_title);
		tv_title.setText("九大行星介绍");
		
		Bundle bundle = getIntent().getExtras();
		int type = bundle.getInt("type");
		if (type == 0) {
			Configuration config = getResources().getConfiguration();
			if(config.orientation == Configuration.ORIENTATION_PORTRAIT){
				showList();
			} else {
				showGrid();
			}
		} else if (type == 1) {
			showList();
		} else {
			showGrid();
		}
	}
	
	private void showList() {
		ViewStub vs_list = (ViewStub) findViewById(R.id.vs_list);
		vs_list.inflate();
		ListView lv_hello = (ListView) findViewById(R.id.lv_hello);
		TitleListAdapter adapter = new TitleListAdapter(this, mStrList);
		lv_hello.setAdapter(adapter);
		lv_hello.setOnItemClickListener(adapter);
		lv_hello.setOnItemLongClickListener(adapter);
	}

	private void showGrid() {
		ViewStub vs_grid = (ViewStub) findViewById(R.id.vs_grid);
		vs_grid.inflate();
		GridView gv_hello = (GridView) findViewById(R.id.gv_hello);
		ContentGridAdapter adapter = new ContentGridAdapter(this, mStrList);
		gv_hello.setAdapter(adapter);
		gv_hello.setOnItemClickListener(adapter);
		gv_hello.setOnItemLongClickListener(adapter);
	}

	@Override
	public void onClick(View v) {
		if (v.getId() == R.id.ib_back) {
			finish();
		}
	}
	
}

样式style

样式在res/values/styles.xml中定义,它适用于下面几种情况: 1、布局文件中存在多个具有相同风格的控件,比如说统一的文本框TextView,都是白底黑字、中号字体、居中显示,这时我们便可在styles.xml定义一种文本样式,然后在各文本框处声明它的style属性。好处一个是减少了布局文件的大小,另一个是方便以后统一修改风格。 2、某些控件在代码中声明时需要手工指定style,例如自定义对话框需要在构造函数中指定样式,参见《Android开发笔记(六十六)自定义对话框》;另一个例子是弹窗PopupWindow在设置伸缩动画方法setAnimationStyle时需要指定动画样式,参见《Android开发笔记(六十五)多样的菜单》。 3、定义页面的主题风格,然后应用到Activity页面。代码中设置主题可通过“setTheme(R.style.***)”完成,布局中设置可在AndroidManifest.xml的activity节点下添加theme属性,如“android:theme="@style/***"”。 下面是在styles.xml中自定义样式的一个例子

代码语言:javascript
复制
    <style name="middle_text">
        <item name="android:textColor">#000000</item>
        <item name="android:textSize">17sp</item>
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
    </style>
    
    <style name="middle_text_center" parent="@style/middle_text">
        <item name="android:layout_gravity">center_horizontal</item>
        <item name="android:gravity">center</item>
    </style>

布局文件中给控件声明风格属性:

代码语言:javascript
复制
        style="@style/middle_text_center"

主题Theme

主题是一种特殊的样式,主题专用于页面,而样式一般运用于控件。主题定义一般放在themes.xml,样式定义一般放在styles.xml。 Android定义了一些系统主题,完整定义的参见sdk自带的themes.xml,常用的几种说明如下: Theme.NoTitleBar : 不显示标题栏,即隐藏ActionBar Theme.Light : 白色背景 Theme.Holo : 浅灰背景 Theme.Black : 黑色背景 Theme.Wallpaper : 壁纸 Theme.Translucent : 透明背景 Theme.Dialog : 对话框 Theme.Panel : 平板 Theme.InputMethod : 输入法 Theme.SearchBar : 搜索框 在代码中给页面运用主题需要在所有视图初始化之前进行,也就是说,setTheme方法必须在setContentView方法之前执行。下面是个代码中设置主题的例子:

代码语言:javascript
复制
setTheme(android.R.style.Theme_Light_NoTitleBar);

在布局中运用主题,只需在activity界面下添加theme属性即可,下面是个布局中添加主题的例子:

代码语言:javascript
复制
android:theme="@android:style/Theme.Dialog"

除了系统自带的主题样式,我们也可以在themes.xml中自定义主题,具体步骤与自定义样式类似。下面是自定义主题时可能变更的窗口属性: android:windowFrame : 窗口框架图像 android:windowBackground : 窗口背景 android:windowNoTitle : 窗口是否不要标题,即不带ActionBar android:windowFullscreen : 窗口是否全屏 android:windowIsTranslucent : 窗口是否半透明 android:windowIsFloating : 窗口是否悬浮 android:windowAnimationStyle : 窗口切换动画的样式 android:windowEnterAnimation : 进入窗口的动画 android:windowExitAnimation : 退出窗口的动画 注意:windowFrame并不只是边框区域,还包括内部窗口,所以如果windowFrame设置为不透明的图像,那么内部窗口也将只显示这幅不透明的图像。 确实这三个属性容易混淆:android:windowFrame、android:windowBackground、android:background,文字描述感觉都说的不清楚,下面针对三个属性分别测试一下,看看究竟都是什么效果: 只有android:windowFrame设置为半透明红色的窗口截图

从截图可以看到,windowFrame的覆盖区域包括窗口与边框,且窗口对内半透明、对外不透明,而边框对外半透明。 只有android:windowBackground设置为半透明红色的窗口截图

从截图可以看到,windowBackground的覆盖区域只有窗口,且窗口对内对外都是半透明。 只有android:background设置为半透明红色的窗口截图

从截图可以看到,background的覆盖区域只有窗口,且窗口对内半透明、对外不透明 点击下载本文用到的优化布局文件的工程代码 点此查看Android开发笔记的完整目录

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016年03月03日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • include/merge
  • ViewStub
  • 样式style
  • 主题Theme
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档