一、現(xiàn)狀
創(chuàng)新互聯(lián)自2013年創(chuàng)立以來,先為孝昌等服務(wù)建站,孝昌等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為孝昌企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。
頁面多狀態(tài)布局是開發(fā)中常見的需求,即頁面在不同狀態(tài)需要顯示不同的布局,實(shí)現(xiàn)的方式也比較多,最簡單粗暴的方式就是在 XML 中先將不同狀態(tài)對應(yīng)的布局隱藏起來,根據(jù)需要改變其可見狀態(tài),如果多個界面公用相同的狀態(tài)布局,缺點(diǎn)也很明顯,繁瑣、重復(fù)、不優(yōu)雅等,類似的實(shí)現(xiàn)也可以使用 ViewStub,這樣性能會更好些。所以我們要做的就是盡可能避免這些方式所導(dǎo)致的問題,更加高效、優(yōu)雅的管理不同的狀態(tài)布局。
二、目標(biāo)
我們要實(shí)現(xiàn)的 StatusView要實(shí)現(xiàn)的主要功能如下:
效果預(yù)覽如下:
preview
三、實(shí)現(xiàn)
這里只對實(shí)現(xiàn)過程中一些比較重要的點(diǎn)進(jìn)行分析。
3.1、初始化
首先有一個最重要的知識點(diǎn)需要明確,XML 布局中的每個View都有其對應(yīng)的父 View,必然在其父View中都有固定的位置,如果是 Activity 對應(yīng)的 XML,那XML根布局View的父View是誰呢?其實(shí)就是一個 id 為 android.R.id.content
的 View,如果是 Fragment 對應(yīng)的 XML,那 XML 根布局 View 的父 View 可以通過 fragment.getView()
方法得到。所以現(xiàn)在我們可以得到XML 中每一個View和對應(yīng)的 LayoutParams 位置信息。
既然有了 View 和其對應(yīng)的 LayoutParams 位置信息,就可以通過其父 View 將指定的子 View 移除掉,然后將 StatusView 添加到被移除的 View 的位置,進(jìn)而就可以控制 StatusView 來切換不同的狀態(tài)布局。
簡單總結(jié)下,就是用 StatusView 替換掉要進(jìn)行多狀態(tài)布局切換的 View,這個 View 可以時 XML 中的任意 View。這也是直接在 Activity、Fragment 中使用 StatusView 要做的核心初始化工作。
那么 StatusView 又是個什么呢?其實(shí)就是一個繼承了 FrameLayout
的 ViewGroup,之所以要繼承 FrameLayout,因?yàn)?StatusView 此時僅僅是作為父容器存在的,并不關(guān)心內(nèi)部各種狀態(tài) View 的具體情況,所以使用 FrameLayout 就夠了,更有通用性。這樣 StatusView 也就可以在 XML 中使用了
先將上邊這部分內(nèi)容轉(zhuǎn)化成代碼:
public class StatusView extends FrameLayout { ...... /** * 在 Activity 中的初始化方法,默認(rèn)頁面的根布局使用多狀態(tài)布局 */ public static StatusView init(Activity activity) { View contentView = ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0); return init(contentView); } /** * 在 Activity 中的初始化方法 * @param viewId 使用多狀態(tài)布局的 ViewId */ public static StatusView init(Activity activity, @IdRes int viewId) { View rootView = ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0); View contentView = rootView.findViewById(viewId); return init(contentView); } /** * 在Fragment中的初始化方法 * @param viewId 使用多狀態(tài)布局的 ViewId */ public static StatusView init(Fragment fragment, @IdRes int viewId) { View rootView = fragment.getView(); View contentView = null; if (rootView != null) { contentView = rootView.findViewById(viewId); } return init(contentView); } /** * 用 StatusView 替換要使用多狀態(tài)布局的 View */ private static StatusView init(View contentView) { if (contentView == null) { throw new RuntimeException("ContentView can not be null!"); } ViewGroup parent = (ViewGroup) contentView.getParent(); if (parent == null) { throw new RuntimeException("ContentView must have a parent view!"); } ViewGroup.LayoutParams lp = contentView.getLayoutParams(); int index = parent.indexOfChild(contentView); parent.removeView(contentView); StatusView statusView = new StatusView(contentView.getContext()); statusView.addView(contentView); statusView.setContentView(contentView); parent.addView(statusView, index, lp); return statusView; } ...... }
如果在 XML 中使用 StatusView 如何進(jìn)行初始化呢,自然是通過 onFinishInflate()
方法:
@Override protected void onFinishInflate() { super.onFinishInflate(); if (getChildCount() == 1) { View view = getChildAt(0); setContentView(view); } }
3.2、狀態(tài)布局的切換
StatusView 默認(rèn)支持 Loading、Empty、Error 三種狀態(tài)布局,加上原始的頁面內(nèi)容布局,一共四種。切換狀態(tài)布局時,我們做法是直接從 StatusView 中移除掉正在顯示的狀態(tài)布局,然后添加要顯示的狀態(tài)布局:
private void switchStatusView(View statusView) { if (statusView == currentView) { return; } removeView(currentView); currentView = statusView; addView(currentView); }
3.3、狀態(tài)布局的懶加載
在APP使用環(huán)境良好的情況下,有些狀態(tài)布局可能根本沒有顯示的機(jī)會,如果在初始化時一股腦的加載出來自然不可取,影響性能,所以我們要做的就是按需加載,即僅在狀態(tài)布局初次顯示時加載并初始化,之后復(fù)用即可:
private View generateStatusView(@LayoutRes int layoutId) { View statusView = viewArray.get(layoutId); if (statusView == null) { statusView = inflate(layoutId); viewArray.put(layoutId, statusView); configStatusView(layoutId, statusView); } return statusView; }
3.4、更自由的用法
一般的多狀態(tài)布局管理都會提供默認(rèn)的 Loading、Empty、Error 三種狀態(tài)布局,并可以自定義對應(yīng)的狀態(tài)布局, 并提供對應(yīng)的開放 api。但這樣會有些局限性,如果有其它業(yè)務(wù)場景的狀態(tài)布局,雖然布局文件可以自定義,但原有的api方法調(diào)用起來難免會有違和感,并不友好!所以有必要在常用業(yè)務(wù)場景的基礎(chǔ)上再提供更加通用的api方法,并不局限于特定的場景。
目前的做法是用狀態(tài)布局和對應(yīng)的索引之間的關(guān)系來實(shí)現(xiàn):
// 添加指定索引對應(yīng)的狀態(tài)布局 statusView.setStatusView(int index, @LayoutRes int layoutId) // 為指定索引的狀態(tài)布局設(shè)置初次顯示的監(jiān)聽事件,用來進(jìn)行狀態(tài)布局的相關(guān)初始化 statusView.setOnStatusViewConvertListener(int index, StatusViewConvertListener listener) // 顯示指定索引的狀態(tài)布局 statusView.showStatusView(int index)
3.5、注意事項(xiàng)
主要的點(diǎn)就這么多了,剩下的就是些屬性配置的內(nèi)容,其實(shí)挺簡單的,更多細(xì)節(jié)和用法可參考GitHub: StatusView
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。
網(wǎng)頁標(biāo)題:Android頁面多狀態(tài)布局管理的開發(fā)
文章路徑:http://aaarwkj.com/article4/jegjie.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供營銷型網(wǎng)站建設(shè)、、手機(jī)網(wǎng)站建設(shè)、搜索引擎優(yōu)化、網(wǎng)站營銷、服務(wù)器托管
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)