Android 頁面多狀態布局管理

一、現狀

頁面多狀態布局是開發中常見的需求,即頁面在不同狀態需要顯示不同的布局,實現的方式也比較多,最簡單粗暴的方式就是在 XML 中先將不同狀態對應的布局隱藏起來,根據需要改變其可見狀態,如果多個界面公用相同的狀態布局,缺點也很明顯,繁瑣、重復、不優雅等,類似的實現也可以使用 ViewStub,這樣性能會更好些。所以我們要做的就是盡可能避免這些方式所導致的問題,更加高效、優雅的管理不同的狀態布局。

二、目標

我們要實現的 StatusView 要實現的主要功能如下:

  • 可在 Activity、Fragment 、XML 中使用,可作用于XML的根布局View或其子View
  • 支持默認的狀態布局,可進行常規配置
  • 可自定義狀態布局
  • 狀態布局懶加載,僅在初次顯示時初始化

效果預覽如下:

三、實現

這里只對實現過程中一些比較重要的點進行分析。

3.1、初始化

首先有一個最重要的知識點需要明確,XML 布局中的每個View都有其對應的父 View,必然在其父View中都有固定的位置,如果是 Activity 對應的 XML,那XML根布局View的父View是誰呢?其實就是一個 id 為android.R.id.content的 View,如果是 Fragment 對應的 XML,那 XML 根布局 View 的父 View 可以通過fragment.getView()方法得到。所以現在我們可以得到XML 中每一個View和對應的 LayoutParams 位置信息。

既然有了 View 和其對應的 LayoutParams 位置信息,就可以通過其父 View 將指定的子 View 移除掉,然后將 StatusView 添加到被移除的 View 的位置,進而就可以控制 StatusView 來切換不同的狀態布局。

簡單總結下,就是用 StatusView 替換掉要進行多狀態布局切換的 View,這個 View 可以時 XML 中的任意 View。這也是直接在 Activity、Fragment 中使用 StatusView 要做的核心初始化工作。

那么 StatusView 又是個什么呢?其實就是一個繼承了FrameLayout的 ViewGroup,之所以要繼承 FrameLayout,因為 StatusView 此時僅僅是作為父容器存在的,并不關心內部各種狀態 View 的具體情況,所以使用 FrameLayout 就夠了,更有通用性。這樣 StatusView 也就可以在 XML 中使用了

先將上邊這部分內容轉化成代碼:

public class StatusView extends FrameLayout {....../*** 在 Activity 中的初始化方法,默認頁面的根布局使用多狀態布局*/public static StatusView init(Activity activity) {View contentView = ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0);return init(contentView);}/*** 在 Activity 中的初始化方法* @param viewId   使用多狀態布局的 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   使用多狀態布局的 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 替換要使用多狀態布局的 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 如何進行初始化呢,自然是通過onFinishInflate()方法:

@Override
protected void onFinishInflate() {super.onFinishInflate();if (getChildCount() == 1) {View view = getChildAt(0);setContentView(view);}
}
復制代碼
3.2、狀態布局的切換

StatusView 默認支持 Loading、Empty、Error 三種狀態布局,加上原始的頁面內容布局,一共四種。切換狀態布局時,我們做法是直接從 StatusView 中移除掉正在顯示的狀態布局,然后添加要顯示的狀態布局:

private void switchStatusView(View statusView) {if (statusView == currentView) {return;}removeView(currentView);currentView = statusView;addView(currentView);
}
復制代碼
3.3、狀態布局的懶加載

在APP使用環境良好的情況下,有些狀態布局可能根本沒有顯示的機會,如果在初始化時一股腦的加載出來自然不可取,影響性能,所以我們要做的就是按需加載,即僅在狀態布局初次顯示時加載并初始化,之后復用即可:

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、更自由的用法

一般的多狀態布局管理都會提供默認的 Loading、Empty、Error 三種狀態布局,并可以自定義對應的狀態布局, 并提供對應的開放 api。但這樣會有些局限性,如果有其它業務場景的狀態布局,雖然布局文件可以自定義,但原有的api方法調用起來難免會有違和感,并不友好!所以有必要在常用業務場景的基礎上再提供更加通用的api方法,并不局限于特定的場景。

目前的做法是用狀態布局和對應的索引之間的關系來實現:

// 添加指定索引對應的狀態布局
statusView.setStatusView(int index, @LayoutRes int layoutId)
// 為指定索引的狀態布局設置初次顯示的監聽事件,用來進行狀態布局的相關初始化
statusView.setOnStatusViewConvertListener(int index, StatusViewConvertListener listener)
// 顯示指定索引的狀態布局
statusView.showStatusView(int index)
復制代碼
3.5、注意事項
  • 當 Fragment 布局文件的根 View 使用 StatusView 時,為避免出現的異常問題,建議在 XML 中初始化!
  • 當直接在 Fragment 中使用時,init()方法需要在onCreateView()之后的生命周期方法中執行!
  • 由于StatusView 繼承自 FrameLayout,所以會多一層布局嵌套。

主要的點就這么多了,剩下的就是些屬性配置的內容,其實挺簡單的,更多細節和用法可參考GitHub:StatusView

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/389493.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/389493.shtml
英文地址,請注明出處:http://en.pswp.cn/news/389493.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Tensorflow入門神經網絡代碼框架

Tensorflow—基本用法 使用圖 (graph) 來表示計算任務.在被稱之為 會話 (Session) 的上下文 (context) 中執行圖.使用 tensor 表示數據.通過 變量 (Variable) 維護狀態.使用 feed 和 fetch 可以為任意的操作(arbitrary operation)賦值或者從其中獲取數據。 ? TensorFlow 是一…

手把手教你把代碼丟入github 中

手把手教你把代碼丟入github 中 作為一個小運維一步步教你們怎么把代碼放入到github 中 首先呢我們下載一個git的客戶端 https://git-scm.com/downloads/ 下載一個最新版的2.16.2 下載后那就安裝吧。如果看不懂英文就選擇默認安裝的方式吧。但是你得記住你的軟件安裝的位置 小…

時間序列模式識別_空氣質量傳感器數據的時間序列模式識別

時間序列模式識別 1. Introduction 2. Exploratory Data Analysis ° 2.1 Pattern Changes ° 2.2 Correlation Between Features 3. Anomaly Detection and Pattern Recognition ° 3.1 Point Anomaly Detection (System Fault) ° 3.2 Collective Anomaly Detection (Externa…

oracle 性能優化 07_診斷事件

2019獨角獸企業重金招聘Python工程師標準>>> 一、診斷事件 診斷事件無官方技術文檔支持,使用存在風險,慎用。使用診斷事件可以獲取問題更多的信息,調整系統運行 特性,啟用某些內部功能。用于系統故障的診斷。跟蹤應…

Tensorflow框架:卷積神經網絡實戰--Cifar訓練集

Cifar-10數據集包含10類共60000張32*32的彩色圖片,每類6000張圖。包括50000張訓練圖片和 10000張測試圖片 代碼分為數據處理部分和卷積網絡訓練部分: 數據處理部分: #該文件負責讀取Cifar-10數據并對其進行數據增強預處理 import os impo…

計算機科學速成課36:自然語言處理

詞性 短語結構規則 分析樹 語音識別 譜圖 快速傅里葉變換 音素 語音合成 轉載于:https://www.cnblogs.com/davidliu2018/p/9149252.html

linux內存初始化初期內存分配器——memblock

2019獨角獸企業重金招聘Python工程師標準>>> 1.1.1 memblock 系統初始化的時候buddy系統,slab分配器等并沒有被初始化好,當需要執行一些內存管理、內存分配的任務,就引入了一種內存管理器bootmem分配器。 當buddy系統和slab分配器初始化好后&…

數據科學學習心得_學習數據科學

數據科學學習心得蘋果 | GOOGLE | 現貨 | 其他 (APPLE | GOOGLE | SPOTIFY | OTHERS) Editor’s note: The Towards Data Science podcast’s “Climbing the Data Science Ladder” series is hosted by Jeremie Harris. Jeremie helps run a data science mentorship startup…

Keras框架:Alexnet網絡代碼實現

網絡思想: 1、一張原始圖片被resize到(224,224,3); 2、使用步長為4x4,大小為11的卷積核對圖像進行卷積,輸出的特征層為96層, 輸出的shape為(55,55,96); 3、使用步長為2的最大池化層進行池化,此時…

PHP對象傳遞方式

<?phpheader(content-type:text/html;charsetutf-8);class Person{public $name;public $age;}$p1 new Person;$p1->name 金角大王;$p1->age 400;//這個地方&#xff0c;到底怎樣?$p2 $p1;$p2->name 銀角大王;echo <pre>;echo p1 name . $p1->n…

微軟Azure CDN現已普遍可用

微軟宣布Azure CDN一般可用&#xff08;GA&#xff09;&#xff0c;客戶現在可以從微軟的全球CDN網絡提供內容。最新版本是對去年五月份發布的公眾預覽版的跟進。\\今年5月&#xff0c;微軟與Verizon和Akamai一起推出了原生CDN產品。現在推出了GA版本&#xff0c;根據發布博文所…

數據科學生命周期_數據科學項目生命周期第1部分

數據科學生命周期This is series of how to developed data science project.這是如何開發數據科學項目的系列。 This is part 1.這是第1部分。 All the Life-cycle In A Data Science Projects-1. Data Analysis and visualization.2. Feature Engineering.3. Feature Selec…

Keras框架:VGG網絡代碼實現

VGG概念&#xff1a; VGG之所以經典&#xff0c;在于它首次將深度學習做得非常“深”&#xff0c;達 到了16-19層&#xff0c;同時&#xff0c;它用了非常“小”的卷積核&#xff08;3X3&#xff09;。 網絡框架&#xff1a; VGG的結構&#xff1a; 1、一張原始圖片被resize…

Django筆記1

內容整理1.創建django工程django-admin startproject 工程名2.創建APPcd 工程名python manage.py startapp cmdb3.靜態文件project.settings.pySTATICFILES_dirs {os.path.join(BASE_DIR, static),}4.模板路徑DIRS > [os.path.join(BASE_DIR, templates),]5.settings中mid…

BZOJ 2003 [Hnoi2010]Matrix 矩陣

題目鏈接 https://www.lydsy.com/JudgeOnline/problem.php?id2003 題解 考慮搜索。 確定了第一行和第一列&#xff0c;那么就確定了整個矩陣&#xff0c;因此搜索的范圍可以降到399個位置。 首先搜索第一行&#xff0c;顯然每個不是第一行第一列的位置都可以由三個位置唯一確定…

Keras框架:resent50代碼實現

Residual net概念 概念&#xff1a; Residual net(殘差網絡)&#xff1a;將靠前若干層的某一層數據輸出直接跳過多層引入到后面數據層的輸入 部分。 殘差神經單元&#xff1a;假定某段神經網絡的輸入是x&#xff0c;期望輸出是H(x)&#xff0c;如果我們直接將輸入x傳到輸出作…

MySQL數據庫的回滾失敗(JAVA)

這幾天在學習MySQL數據的知識&#xff0c;有一個小測試&#xff0c;用來測試數據庫的提交和回滾。 剛開始的時候真的沒把這個當回事&#xff0c;按照正常的步驟來講的話&#xff0c;如下所示&#xff0c;加載驅動&#xff0c;獲取數據庫的連接&#xff0c;并且把數據庫的自動提…

條件概率分布_條件概率

條件概率分布If you’re currently in the job market or looking to switch careers, you’ve probably noticed an increase in popularity of Data Science jobs. In 2019, LinkedIn ranked “data scientist” the №1 most promising job in the U.S. based on job openin…

MP實戰系列(十七)之樂觀鎖插件

聲明&#xff0c;目前只是僅僅針對3.0以下版本&#xff0c;2.0以上版本。 意圖&#xff1a; 當要更新一條記錄的時候&#xff0c;希望這條記錄沒有被別人更新 樂觀鎖實現方式&#xff1a; 取出記錄時&#xff0c;獲取當前version 更新時&#xff0c;帶上這個version 執行更新時…

二叉樹刪除節點,(查找二叉樹最大值節點)

從根節點往下分別查找左子樹和右子樹的最大節點&#xff0c;再比較左子樹&#xff0c;右子樹&#xff0c;根節點的大小得到結果&#xff0c;在得到左子樹和右子樹最大節點的過程相似&#xff0c;因此可以采用遞歸的 //樹節點結構 public class TreeNode { TreeNode left;…