Original title: Functional operations over views in ViewGroup using Kotlin
Original link: http://antonioleiva.com/functional-operations-viewgroup-kotlin/
Original Antonio Leiva (http://antonioleiva.com/about/)
Published in the original: 2015-07-29
Collections, iterations, arrays, sequences ... All of these share a useful set of functions that help transform, sort, and manipulate their elements . However, due to the way the class is constructed, some functions are not available in the Android SDK.
For example, we cannot directly obtain ViewGroup
internal View list, so these operations are not available. But not everything has been lost. In Kotlin, we have a way to prepare any data for these operations . The trick is simple: we just need to create one Sequence
. In our case, sequence will be a set of orderly View
. We just need to implement a function that returns it Iterator
.
if we have Sequence
a , the functional field of operation opens the door for us to use them. So let's start with it.
Note: Read the end of the article
As lakedaemon666 suggested in the comments, there is an easier way to get the same results without sequence. I will keep the original record, but I suggest you look at the alternative solution.
Create a viewgroup sequence
As mentioned earlier, we will create an iterator (iterator), which must know if there is a next item, which is the next one. We also create an extension function that provides an easy way to do the work for any viewgroup and inheriting classes:
1Fun Viewgroup.assequence (): sequence<view> = object:sequence<view> {2 3Override Fun iterator (): iterator<view> = object:iterator<view> {4 Privatevar nextvalue:view? =NULL5 Privatevar done =false6 Privatevar position:int = 07 8Override PublicFun Hasnext (): Boolean {9 if(NextValue = =NULL&&!Done ) {TenNextValue =Getchildat (position) Oneposition++ A if(NextValue = =NULL) Done =true - } - returnNextValue! =NULL the } - - override Fun Next (): View { - if(!Hasnext ()) { + Thrownosuchelementexception () - } +Val answer =NextValue ANextValue =NULL at returnanswer!! - } - } -}
Retrieving view recursive lists
It is useful to get a list of views and function on them. Therefore, we can first create a top-level view list and then use it recursively to retrieve ViewGroup
The In-view in a hierarchical manner.
let us for ViewGroup
Create a new Extended Properties . Extended properties are very similar to extension functions and can be used with any class:
1 public Val viewgroup.views:list<view>2 get () = Assequence (). ToList ()
We can use this to create a recursive function that returns the layout of any ViewGroup
all View
the inside :
1 public Val viewgroup.viewsrecursive:list<view>2 get () = FlatMap {3 when (it) {4-viewgroup- it.viewsrecursive5 else -listof (IT)6 }7 }
flatMap
, we convert multiple lists of all results to a list. It will traverse any view, and if it is viewgroup, it will also traverse its own view. Otherwise, a list of only one item is returned.
Usage examples
Now, we get the viewRecursive
properties and do whatever we want to do. Here you can see two examples. I created such a simple layout:
1 <Relativelayoutxmlns: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"Ten Tools:context=". Mainactivity "> One A <TextView - Android:layout_width= "Wrap_content" - Android:layout_height= "Wrap_content" the Android:text= "@string/hello_world"/> - - <Framelayout - Android:layout_width= "Match_parent" + Android:layout_height= "Wrap_content" - android:layout_centerinparent= "true"> + A <TextView at Android:layout_width= "Wrap_content" - Android:layout_height= "Wrap_content" - Android:text= "Hello Java"/> - - <TextView - Android:layout_width= "Wrap_content" in Android:layout_height= "Wrap_content" - android:layout_gravity= "Center_horizontal" to Android:text= "Hello Kotlin"/> + - <TextView the Android:layout_width= "Wrap_content" * Android:layout_height= "Wrap_content" $ android:layout_gravity= "End"Panax Notoginseng Android:text= "Hello Scala"/> - the </Framelayout> + A <LinearLayout the Android:layout_width= "Match_parent" + Android:layout_height= "Wrap_content" - Android:layout_alignparentbottom= "true" $ android:orientation= "Horizontal"> $ - <CheckBox - Android:layout_width= "Wrap_content" the Android:layout_height= "Wrap_content" - Android:text= "Check 1"/>Wuyi the <CheckBox - Android:layout_width= "Wrap_content" Wu Android:layout_height= "Wrap_content" - Android:text= "Check 2"/> About $ <CheckBox - Android:layout_width= "Wrap_content" - Android:layout_height= "Wrap_content" - Android:text= "Check 3"/> A + <CheckBox the Android:layout_width= "Wrap_content" - Android:layout_height= "Wrap_content" $ Android:text= "Check 4"/> the the </LinearLayout> the the </Relativelayout>
For example, MainActivity.onCreate()
中,
You can apply this code. It Hello Kotlin!
converts the string to uppercase, and the Even check box is selected:
1Val Container:viewgroup =Find (R.id.container)2Val views =container.viewsrecursive3 4 //Set Kotlin TextView to Upper5Val Kotlintext =Views.first {6It is TextView && it.text.toString (). Contains ("Kotlin")7 } as TextView8Kotlintext.text =kotlinText.text.toString (). toUpperCase ()9 Ten //Set even checkboxes as checked, and odd as unchecked One Views Filter { A It is CheckBox - } forEach { - With (it as CheckBox) { theVal number = Text.tostring (). Removeprefix ("Check"). ToInt () -setchecked (number% 2 = = 0) - } -}
Alternative Solutions
As lakedaemon666 mentioned in the comments (thank you for explaining), if we then traverse the entire sequence, then creating sequence is meaningless. For example, when a file is read by row, sequence is lazy iteration. Only the necessary items are required. And we're going to use all the items, so a simple list is enough.
In addition, there are many simple ways to generate a list of views. We can rely on the range to produce the indexed list of views and map them to the list of views we need. All this is one line:
1 public Val viewgroup.views:list<view>2 get () = (0..getChildCount ()-1) Map {Getchildat (it ) }
Summarize
This is a boring example, but this concept may make all your code functional and stop relying on loops and other control flows that are typically iterative programming.
remember from the book I wrote Android Developer Kotlin, you can learn the Kotlin of this and many other abilities, and you will learn Kotlin by creating an Android app starting from 0.
Use Kotlin to function the view of ViewGroup