⑴ android 布局優化之 ViewStub、 include、merge
文章、布局優化神器 include 、merge、ViewStub 標簽詳解
Tips:
include 標簽使用:
//include_test.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="@string/textview"
android:textSize="24sp"/>
<EditText
android:id="@+id/editText"
android:hint="@string/divide"
android:layout_width="300dp"
android:layout_height="wrap_content"/>
</LinearLayout>---------------------------------------------------------------
//include_text_relative
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
>
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="TextView_Relative"
android:textSize="24sp"/>
<EditText
android:id="@+id/editText"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_below="@+id/textView"
android:hint="@string/divide"/>
</RelativeLayout>
---------------------------------------------------------------
//include_toolbar.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/tb_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#00f"
app:theme="@style/AppTheme"
app:title="這是一個 ToolBar"app:titleTextColor="@android:color/white"/>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<!--測試 layout 和<include>都設置 ID 的情況-->
<include
android:id="@+id/tb_toolbar"
layout="@layout/include_toolbar"/>
<!--如果只有單個 include 這樣寫就可以,載入的布局的子 View,直接 findViewByID 就能找
到-->
<include layout="@layout/include_text"/>
<!--如果有多個 include,需要添加 ID 屬性-->
<include
android:id="@+id/include_text1"
layout="@layout/include_text"/>
<!--這個 layout 用 RelativeLayout 實現-->
<!--如果要使用 layout_margin 這樣的屬性,要同時加上 layout_w/h 屬性,不然沒反應-->
<include
android:id="@+id/include_text2"
layout="@layout/include_text_relative"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="50dp"/>
</LinearLayout>
private void initView() {
//如果 include 布局根容器和 include 標簽中的 id 設置的是不同的值,這里獲取的
mToolbar 值將為 nullToolbar mToolbar = (Toolbar) findViewById(R.id.tb_toolbar);
setSupportActionBar(mToolbar);
//普通 include 標簽用法,直接拿子 View 屬性實現
TextView textView = (TextView) findViewById(R.id.textView);
textView.setText("不加 ID 實現的 include 標簽");
//多個 include 標簽用法,添加 ID,findViewByID 找到 layout,再找子控制項
View view_include = findViewById(R.id.include_text1);
TextView view_include_textView = (TextView) view_include.findViewById(R.id.textView);
view_include_textView.setText("加了 ID 實現的 include 標簽");
//多個 include 標簽用法,添加 ID,findViewByID 找到 layout,再找子控制項
View view_include_Relative = findViewById(R.id.include_text2);
TextView view_textView_relative =(TextView) view_include_Relative.findViewById(R.id.textView);
view_textView_relative.setText("加了 ID 實現的 include 標簽(RelaviteLayout)");
}
include 標簽 Demo 效果圖
==include 使用注意==
merge標簽主要用於輔助include標簽,在使用include後可能導致布局嵌套過
多,多餘的 layout 節點或導致解析變慢(可通過 hierarchy viewer 工具查看布
局的嵌套情況)官方文檔說明:merge 用於消除視圖層次結構中的冗餘視圖,例如根布局是
Linearlayout,那麼我們又 include 一個 LinerLayout 布局就沒意義了,反而會
減慢 UI 載入速度
merge 標簽常用場景: .
根布局是 FrameLayout 且不需要設置 background 或 padding 等屬性,可
以用merge代替,因為 Activity的 ContentView 父元素就是FrameLayout,
所以可以用 merge 消除只剩一個.
.某布局作為子布局被其他布局include時,使用merge當作該布局的頂節點,
這樣在被引入時頂結點會自動被忽略,而將其子節點全部合並到主布局中.
.自定義 View 如果繼承 LinearLayout(ViewGroup),建議讓自定義 View 的
布局文件根布局設置成 merge,這樣能少一層結點.
.merge 標簽使用:
在 XML 布局文件的根布局如 RelativeLayout 直接改成 merge 即可
merge 標簽使用前後 Hierarchy Viewer 截圖
FrameLayout 替換 merge 前
FrameLayout 替換 merge 後
include 標簽對應 layout 根布局 替換 merge 前
include 標簽對應 layout 根布局 替換 merge 後
==merge 使用注意==
ViewStub 標簽最大的優點是當你需要時才會載入,使用它並不會影響 UI 初始
化時的性能.各種不常用的布局像進度條、顯示錯誤消息等可以使用 ViewStub
標簽,以減少內存使用量,加快渲染速度.ViewStub 是一個不可見的,實際上是把
寬高設置為 0 的 View.效果有點類似普通的 view.setVisible(),但性能體驗提高
不少
第一次初始化時,初始化的是 ViewStub View,當我們調用 inflate()或
setVisibility()後會被 remove 掉,然後在將其中的 layout 加到當前 view
hierarchy 中
ViewStub 官方文檔鏈接
//官方例子
<ViewStub
android:id="@+id/stub_import"
<!--android:inflateId:重寫 ViewStub 的父布局控制項的 Id-->
android:inflatedId="@+id/panel_import"
< <!--android:layout:設置 ViewStub 被 inflate 的布局-->
android:layout="@layout/progress_overlay"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom" />
-------------------------------------------------//當你想載入布局時,可以使用下面其中一種方法:
((ViewStub)
findViewById(R.id.stub_import)).setVisibility(View.VISIBLE);
// or
View importPanel = ((ViewStub)
findViewById(R.id.stub_import)).inflate();
判斷 ViewStub(做單例)是否已經載入過:
1. 如果通過 setVisibility 來載入,那麼通過判斷可見性即可;
2. 如果通過 inflate()來載入,判斷 ViewStub 的 ID 是否為 null 來判斷
(findViewById(…))
public class ViewStubActivity extends AppCompatActivity
implements View.OnClickListener, ViewStub.OnInflateListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);setContentView(R.layout.activity_view_stub);
}
private View networkErrorView;
private void showNetError() {
// not repeated infalte
if (networkErrorView != null) {
//setVisibility()方式載入布局,載入次數不限
networkErrorView.setVisibility(View.VISIBLE);
return;
}
//inflate()方式載入布局,只能載入一次
ViewStub stub = (ViewStub)
findViewById(R.id.network_error_layout);
stub.setOnInflateListener(this);networkErrorView = stub.inflate();
Button networkSetting = (Button)
networkErrorView.findViewById(R.id.network_miss);
networkSetting.setOnClickListener(this);
Button refresh = (Button)
findViewById(R.id.network_refresh);
refresh.setOnClickListener(this);
}
private void showNormal() {
if (networkErrorView != null) {
networkErrorView.setVisibility(View.GONE);
}
}
public void show(View view) {showNetError();
}
public void refresh(View view) {
showNormal();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.network_miss:
Toast.makeText(this, "network_miss",
Toast.LENGTH_SHORT).show();
break;
case R.id.network_refresh:
Toast.makeText(this, "network_refresh",
Toast.LENGTH_SHORT).show();break;
}
}
/**
*
* @param stub 當前待 inflate 的 ViewStub 控制項
* @param inflated 當前被 inflate 的 View 視圖
*/
@Override
public void onInflate(ViewStub stub, View inflated) {
}
}
ViewStub 標簽 Demo 效果圖:
ViewStub 標簽使用前後 Hierarchy Viewer 截圖
ViewStub 標簽使用前:
ViewStub 標簽使用後:
==ViewStub 標簽使用注意==
擴展:
Space 組件
在 ConstraintLayout 出來前,我們寫布局都會使用到大量的 margin 或
padding,但是這種方式可讀性會很差,加一個布局嵌套又會損耗性能
鑒於這種情況,我們可以使用space,使用方式和View一樣,不過主要用來佔位置,
不會有任何顯示效果
⑵ Android-ConstraintSet進階-不同顯示效果
在Android應用開發中,頁面的動態顯示效果是提高用戶體驗的關鍵。為了實現頁面中不同部分基於用戶狀態的顯示,通常有多種布局策略。本文將探討如何利用ConstraintSet進行高級布局以實現不同顯示效果。
首先,介紹兩種常見的布局策略:
1. 使用相對布局(RelativeLayout)和visibility屬性來控制元素的顯示和隱藏。這種方法直接通過代碼實現元素的可見性管理,易於理解和操作,但缺點是布局文件與代碼耦合度高。
2. 定義多套布局文件,並利用include方式動態添加到主布局中。這種方法使布局更靈活,但也增加了文件管理和維護的復雜性。
然而,隨著技術的發展,ConstraintLayout提供了更強大的布局管理工具,尤其是ConstraintSet。它允許我們為布局中的元素創建復雜的約束關系,從而實現更動態和靈活的布局效果。
以按鈕為例,利用ConstraintSet可以實現以下效果:
1. 顯示兩個按鈕時,它們與左上角圖標的對齊以及兩個按鈕之間的間距可以通過設置約束來實現。
2. 當需要隱藏左側按鈕時,右側按鈕可以自動靠左邊顯示,並保持與左邊的間距。
在布局中,通過設置按鈕間的marginLeft代替marginRight,可以在隱藏左側按鈕時保持右側按鈕與左側的間距。這種布局方式比直接使用marginRight更為靈活。
面對布局設計時的間距問題,尤其是高度內容包裹的布局,設置間距不生效的情況,關鍵在於布局約束的完整性。通常,為避免這種問題,應確保布局中的所有元素都具有上下左右的約束。這不僅提高了布局的可預測性和一致性,還有助於避免布局內部的控制項受到干擾。
使用ConstraintSet時,要確保約束的全面性。當布局中包含高度內容時,確保所有元素都有上下約束,同時避免遺漏。否則,布局渲染時可能會因缺少參考而出現問題。
總的來說,通過ConstraintSet,開發者能夠更高效地管理復雜的布局約束,實現動態的顯示效果。它不僅提高了布局的靈活性,也簡化了代碼的維護。當然,針對具體問題,開發者還需要根據實際情況靈活應用各種布局策略,以實現最佳的用戶體驗。
⑶ Android布局優化的幾種方式
1. include/merge
布局優化中常常用到include/merge標簽,include的含義類似C代碼中的include,意思是直接把指定布局片段包含進當前的布局文件。include適用於多個布局文件中存在相同的xml片段,比如說相同的標題欄、相同的廣告欄、相同的進度欄等等。
2. ViewStub
在一個頁面上根據不同條件展示不同的控制項,我們常常會設置控制項的可視屬性,比如調用指定控制項的setVisibility方法,若需展示則設置View.VISIBLE,若需隱藏則設置View.GONE。不過gone的控制項只是看不到罷了,實際UI渲染時還是會被載入。要想事先不載入,在條件符合時才載入,就得用到標簽ViewStub。
3. style樣式
樣式在res/values/styles.xml中定義,它適用於下面幾種情況:
1、布局文件中存在多個具有相同風格的控制項,比如說統一的文本框TextView,都是白底黑字、中號字體、居中顯示,這時我們便可在styles.xml定義一種文本樣式,然後在各文本框處聲明它的style屬性。好處一個是減少了布局文件的大小,另一個是方便以後統一修改風格。
2、某些控制項在代碼中聲明時需要手工指定style,例如自定義對話框需要在構造函數中指定樣式;另一個例子是彈窗PopupWindow在設置伸縮動畫方法setAnimationStyle時需要指定動畫樣式。
3、定義頁面的主題風格,然後應用到Activity頁面。代碼中設置主題可通過「setTheme(R.style.)」完成,布局中設置可在AndroidManifest.xml的activity節點下添加theme屬性,如「android:theme=」@style/「」。
4. 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 : 搜索框