成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

ViewGroup 默認順序繪制子 View,如何修改?什么場景需要修改繪制順序?

開發 架構
View 的三大流程:測量、布局、繪制,我想大家應該都爛熟于心。而在繪制階段,ViewGroup 不光要繪制自身,還需循環繪制其一眾子 View,這個繪制策略默認為順序繪制,即 [0 ~ childCount)。

 [[333892]]

一、序

大家好,我是承香墨影,許久不見,甚是想念!

今天我們來聊聊 View 繪制流程的一個小細節,自定義繪制順序。

View 的三大流程:測量、布局、繪制,我想大家應該都爛熟于心。而在繪制階段,ViewGroup 不光要繪制自身,還需循環繪制其一眾子 View,這個繪制策略默認為順序繪制,即 [0 ~ childCount)。

這個默認的策略,有辦法調整嗎?例如修改成 (childCount ~ 0],或是修成某個 View 最后繪制。同時又有什么場景需要我們做這樣的修改?

需要注意的是,繪制順序會影響覆蓋順序,同時也會影響 View 的事件分發,這些都是關聯影響的,可謂是牽一發而動全身。

今天就來聊聊這個問題。

二、TV App 的 Item 處理

修改 View 的繪制順序,在日常開發中,基本用不到。眾多手機端 App 的 UI 設計,大部分采用扁平化的設計思想,除非是一些很特別的自定義 View,多數情況下,我們無需考慮 View 的默認繪制順序。

這也很好理解,正常情況下,ViewGroup 中后添加的 View,視覺上就是應該覆蓋在之前的 View 之上。

但是有一個場景的設計,很特別,那就是 Android TV App。

在 TV 的設計上,因為需要遙控器按鍵控制,為了更豐富的視覺體驗,是需要額外處理 View 對焦點狀態的變化的。

例如:獲取焦點的 ItemView 整個高亮,放大再加個陰影,都是很常見的設計。

那么這就帶來一個問題,正常我們使用 RecyclerView 實現的列表效果,當 Item 之間的間距過小時,單個 Item 被放大就會出現遮蓋的效果。

例如上圖所示,一個很常見的焦點放大高亮的設計,但卻被后面的 View 遮蓋了。

這樣的情況,如何解決呢?

拍腦袋想,既然是間距太小了,那我們就拉大間距就好了。修改一個屬性解決一個需求,設計師哭暈在工位上。

不過確實有一些設計效果,間距足夠,也就不存在遮蓋的現象,例如 Bilibili TV 端的部分頁面。

但是我們不能只靠改間距解決問題,多數情況下,設計師留給我們的間距并不多。大部分 TV App 是這樣的。

既然逃不掉,那就研究一下如何解決。

三、修改繪制順序原理

修改繪制順序,其實很簡單,Android 已經為我們留出了擴展點。

我們知道,ViewGroup 通過其成員 mChildren 數組,存儲子 View。而在 ViewGroup 繪制子 View 的 dispatchDraw() 方法循環中,并不是直接利用索引從 mChildren 數組中取值的。

  1. @Override 
  2. protected void dispatchDraw(Canvas canvas) { 
  3.   // ... 
  4.   final ArrayList<View> preorderedList = usingRenderNodeProperties 
  5.         ? null : buildOrderedChildList(); 
  6.   final boolean customOrder = preorderedList == null 
  7.         && isChildrenDrawingOrderEnabled(); 
  8.   for (int i = 0; i < childrenCount; i++) { 
  9.     // ... 
  10.     final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder); 
  11.     // 并非直接從 mChildren 中獲取 
  12.     final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex); 
  13.     if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) { 
  14.         more |= drawChild(canvas, child, drawingTime); 
  15.     } 
  16.   } 
  17.   // ... 

可以看到,child 并非是從 mChildren 中直取,而是通過 getAndVerifyPreorderedView() 獲得,它的參數除了 children 外,還有一個 preorderedList 的 ArrayList,及子 View 的索引。

  1. private static View getAndVerifyPreorderedView(ArrayList<View> preorderedList, 
  2.         View[] children, 
  3.         int childIndex) { 
  4.   final View child; 
  5.   if (preorderedList != null) { 
  6.     child = preorderedList.get(childIndex); 
  7.     if (child == null) { 
  8.         throw new RuntimeException("Invalid preorderedList contained null child at index " 
  9.                 + childIndex); 
  10.     } 
  11.   } else { 
  12.     child = children[childIndex]; 
  13.   } 
  14.   return child; 

在其中,若 preorderedList 不為空,則從其中獲取子 View,反之則還是從 children 中獲取。

回到前面 dispatchDraw() 中,這里使用的 preorderedList 關鍵列表,來自 buildOrderedChildList(),在方法中通過 getAndVerifyPreorderedIndex() 獲取對應子 View 的索引,此方法需要一個 Boolean 類型的 customOrder,即表示是否需要自定義順序。

  1. ArrayList<View> buildOrderedChildList() { 
  2.   // ... 
  3.   final boolean customOrder = isChildrenDrawingOrderEnabled(); 
  4.   for (int i = 0; i < childrenCount; i++) { 
  5.     // add next child (in child orderto end of list 
  6.     final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder); 
  7.     final View nextChild = mChildren[childIndex]; 
  8.     final float currentZ = nextChild.getZ(); 
  9.     // insert ahead of any Views with greater Z 
  10.     int insertIndex = i; 
  11.     while (insertIndex > 0 && mPreSortedChildren.get(insertIndex - 1).getZ() > currentZ) { 
  12.         insertIndex--; 
  13.     } 
  14.     mPreSortedChildren.add(insertIndex, nextChild); 
  15.   } 
  16.   return mPreSortedChildren; 

buildOrderedChildList() 的邏輯就是按照 Z 軸調整 children 順序,Z 軸值相同則參考 customOrder 的配置。

通常 ViewGroup 中的子 View,Z 值一致,所以關鍵參數是 customOrder 開關。

從代碼上了解到 customOrder 是通過 isChildrenDrawingOrderEnabled() 方法獲取,與之對應的是 setChildrenDrawingOrderEnabled() 可以設置 customOrder 的取值。

也就是說,如果我們要調整順序,只需 2 步調整:

調用 setChildrenDrawingOrderEnable(true) 開啟自定義繪制順序

重寫 getChildDrawingOrder() 修改 View 的取值索引

四、實例

最后,我們寫個 Demo,重寫 RecycleView 的 getChildDrawingOrder() 方法,來實現獲得焦點的 View 最后繪制。

  1. @Override 
  2. protected int getChildDrawingOrder(int childCount, int i) { 
  3.   View view = getLayoutManager().getFocusedChild(); 
  4.   if (null == view) { 
  5.     return super.getChildDrawingOrder(childCount, i); 
  6.   } 
  7.   int position = indexOfChild(view); 
  8.   if (position < 0) { 
  9.     return super.getChildDrawingOrder(childCount, i); 
  10.   } 
  11.   if (i == childCount - 1) { 
  12.     return position; 
  13.   } 
  14.   if (i == position) { 
  15.     return childCount - 1; 
  16.   } 
  17.   return super.getChildDrawingOrder(childCount, i); 

別忘了還需要調用 setChildrenDrawingOrderEnabled(true) 開啟自定義繪制順序。

此時,焦點放大時,就不會被其他 View 遮擋。

 

責任編輯:武曉燕 來源: 51CTO專欄
相關推薦

2010-10-08 12:03:03

修改mysql字段

2011-08-23 09:33:19

Ubuntu系統托盤

2017-08-21 21:36:23

AndroidViewJava

2016-07-29 11:21:16

Ubuntulinux程序

2010-06-09 08:59:30

UML活動圖

2010-08-11 14:47:54

Flex樣式

2021-04-26 07:53:04

繪制流程任務

2010-09-07 16:05:23

SQL語句刪除

2013-12-10 10:27:04

密碼

2010-06-08 10:35:38

UML圖

2010-06-09 18:56:44

UML用例圖

2023-05-19 08:01:57

Go 語言map

2017-04-27 20:30:33

Android動畫技巧

2011-07-25 14:54:53

iPhone iPhone開發 View

2010-11-09 15:38:24

SQL Server默

2011-04-07 11:24:17

Distance 命令路由OSPF

2009-09-03 10:26:07

C#修改DataRea

2010-09-28 10:23:36

SQL修改字段

2010-07-12 11:36:32

UML活動圖

2010-06-11 09:46:55

UML順序圖
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美一区二区激情三区 | 久久99精品久久 | 日本欧美在线 | 一级二级三级黄色 | 中文字幕乱码视频32 | 日韩av啪啪网站大全免费观看 | 久久精品91 | 亚洲a视| 久久综合亚洲 | h视频免费在线观看 | 久久伦理中文字幕 | 中文字幕第5页 | 欧美日韩在线一区二区 | 在线观看亚洲精品视频 | av国产在线观看 | 在线日韩 | 欧美精品a∨在线观看不卡 欧美日韩中文字幕在线播放 | 精品国产伦一区二区三区观看体验 | 亚洲精品99 | 日韩成人免费在线视频 | 1000部精品久久久久久久久 | 久久久性色精品国产免费观看 | 欧美一级二级在线观看 | 一区二区三区电影网 | 国产午夜精品一区二区三区嫩草 | 欧美区日韩区 | 盗摄精品av一区二区三区 | 国产精品一区二区三区久久久 | 日韩午夜一区二区三区 | 成人免费看 | 久久麻豆精品 | 中文字幕一区二区三区四区五区 | 久久免费电影 | 国产丝袜一区二区三区免费视频 | 亚洲欧美综合 | 亚洲电影一区 | 成人一级毛片 | 国产精品久久久久一区二区三区 | 国产一区二区三区在线看 | 一区二区片 | www.黄网 |