Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> 使用Kotlin對ViewGroup的視圖進行函數使操作,kotlinviewgroup

使用Kotlin對ViewGroup的視圖進行函數使操作,kotlinviewgroup

編輯:關於android開發

使用Kotlin對ViewGroup的視圖進行函數使操作,kotlinviewgroup


原文標題:Functional operations over Views in ViewGroup using Kotlin

原文鏈接:http://antonioleiva.com/functional-operations-viewgroup-kotlin/

原文作者:Antonio Leiva(http://antonioleiva.com/about/)

原文發布:2015-07-29

 

 

集合、迭代、數組、序列 ... 所有這些共用一套好用的函數,這組函數可幫助對它們的元素進行轉換、排序以及其它操作。但是,由於類的構造方法,在Android SDK中,有部分函數還不能用。

例如,我們不能直接獲得ViewGroup內部視圖列表,所以這些操作是不可能使用的。但是並非所有一切都失去了。在Kotlin中,我們有方法為這些操作准備任何數據。訣竅簡單:我們只需要創建一個Sequence。在我們的例子中,Sequence將是一組有序的View。我們只需要實現一個函數,其返回Iterator

如果我們有了Sequence,函數式操作領域就為我們打開了使用它們的大門。所以讓我們從它開始。

注:閱讀文章結尾

如lakedaemon666在評論中所建議的那樣,有一個不用Sequence的更簡單的方法可以獲得同樣的結果。我會保留原文記錄,但是建議你看看替代的解決方案。

 

創建ViewGroup的Sequence

如前所述,我們將創建迭代器(iterator),它必須知道是否有下一項,下一項是哪個。我們還創建一個擴展函數,為了任何 ViewGroup 和繼承類提供一個簡單的方法做那項工作:

 1 fun ViewGroup.asSequence(): Sequence<View> = object : Sequence<View> {
 2  
 3     override fun iterator(): Iterator<View> = object : Iterator<View> {
 4         private var nextValue: View? = null
 5         private var done = false
 6         private var position: Int = 0
 7  
 8         override public fun hasNext(): Boolean {
 9             if (nextValue == null && !done) {
10                 nextValue = getChildAt(position)
11                 position++
12                 if (nextValue == null) done = true
13             }
14             return nextValue != null
15         }
16  
17         override fun next(): View {
18             if (!hasNext()) {
19                 throw NoSuchElementException()
20             }
21             val answer = nextValue
22             nextValue = null
23             return answer!!
24         }
25     }
26 }

 

檢索視圖遞歸列表

獲得一個視圖列表,並對其進行函數操作是非常有用的。因此,我們可以先創建頂層視圖列表,然後,用它以遞歸方式逐級檢索ViewGroup中視圖。

讓我們為ViewGroup創建新擴展屬性。擴展屬性非常類似擴展函數,可用於任何類:

1 public val ViewGroup.views: List<View>
2     get() = asSequence().toList()

 

我們可以用這,創建遞歸函數,它返回布局中任何ViewGroup內部的所有View

1 public val ViewGroup.viewsRecursive: List<View>
2     get() = views flatMap {
3         when (it) {
4             is ViewGroup -> it.viewsRecursive
5             else -> listOf(it)
6         }
7     }

 

flatMap,我們把全部結果的多個列表轉換到一個列表中。它將遍歷任何視圖;如果是ViewGroup,它還會遍歷自己的視圖。否則,就返回僅有一項的列表。

 

用法實例

現在,我們得到viewRecursive屬性,執行我們想要的任何操作。這裡你可以看到兩個例子。我創建這樣一個簡單的布局:

1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:id="@+id/container" 4 android:layout_width="match_parent" 5 android:layout_height="match_parent" 6 android:paddingBottom="@dimen/activity_vertical_margin" 7 android:paddingLeft="@dimen/activity_horizontal_margin" 8 android:paddingRight="@dimen/activity_horizontal_margin" 9 android:paddingTop="@dimen/activity_vertical_margin" 10 tools:context=".MainActivity"> 11 12 <TextView 13 android:layout_width="wrap_content" 14 android:layout_height="wrap_content" 15 android:text="@string/hello_world"/> 16 17 <FrameLayout 18 android:layout_width="match_parent" 19 android:layout_height="wrap_content" 20 android:layout_centerInParent="true"> 21 22 <TextView 23 android:layout_width="wrap_content" 24 android:layout_height="wrap_content" 25 android:text="Hello Java"/> 26 27 <TextView 28 android:layout_width="wrap_content" 29 android:layout_height="wrap_content" 30 android:layout_gravity="center_horizontal" 31 android:text="Hello Kotlin"/> 32 33 <TextView 34 android:layout_width="wrap_content" 35 android:layout_height="wrap_content" 36 android:layout_gravity="end" 37 android:text="Hello Scala"/> 38 39 </FrameLayout> 40 41 <LinearLayout 42 android:layout_width="match_parent" 43 android:layout_height="wrap_content" 44 android:layout_alignParentBottom="true" 45 android:orientation="horizontal"> 46 47 <CheckBox 48 android:layout_width="wrap_content" 49 android:layout_height="wrap_content" 50 android:text="Check 1"/> 51 52 <CheckBox 53 android:layout_width="wrap_content" 54 android:layout_height="wrap_content" 55 android:text="Check 2"/> 56 57 <CheckBox 58 android:layout_width="wrap_content" 59 android:layout_height="wrap_content" 60 android:text="Check 3"/> 61 62 <CheckBox 63 android:layout_width="wrap_content" 64 android:layout_height="wrap_content" 65 android:text="Check 4"/> 66 67 </LinearLayout> 68 69 </RelativeLayout>

 

 例如,在MainActivity.onCreate()中,可應用這段代碼。它將Hello Kotlin!串轉換為大寫字母,選中偶數復選框:

 1 val container: ViewGroup = find(R.id.container)
 2 val views = container.viewsRecursive
 3  
 4 // Set Kotlin TextView to Upper
 5 val kotlinText = views.first {
 6     it is TextView && it.text.toString().contains("Kotlin")
 7 } as TextView
 8 kotlinText.text = kotlinText.text.toString().toUpperCase()
 9  
10 // Set even checkboxes as checked, and odd as unchecked
11 views filter {
12     it is CheckBox
13 } forEach {
14     with(it as CheckBox) {
15         val number = text.toString().removePrefix("Check ").toInt()
16         setChecked(number % 2 == 0)
17     }
18 }

 

 

替代的解決方案

如lakedaemon666在評論中所提及的那樣(謝謝解釋),如果之後我們遍歷整個sequence,那麼創建sequence就沒有什麼意義了。例如,當按行讀取文件時,sequence是懶惰迭代。只有要求必要的項目。而我們卻要使用所有項,所以簡單的列表就足夠了。

另外,有許多簡單的方法可以產生視圖列表。我們可以依賴值域產生視圖的索引列表,將它們映射到我們需要的視圖列表中。所有這一切就一行:

1 public val ViewGroup.views: List<View>
2     get() = (0..getChildCount() - 1) map { getChildAt(it) }

 

總結

這是個無聊的例子,但是這個概念或許可使你的所有代碼函數化,停止依靠那些典型迭代式編程的循環和其它控制流。

記住從我寫的書《Android開發者的Kotlin》中,你能夠學習到Kotlin的這點以及許多其它能力,你將通過從0開始創建Android APP學習Kotlin。

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved