Topic description
Given the root node of the layout, it is required to set the background of all controls of type Button to red without recursion.
analyze
For the layout in Android, there are two types of nodes, one is the ViewGroup layout, and the other is the View control, which is organized according to a tree-like structure (note that it is not a binary tree).
For the traversal of the control, it can be transformed into the traversal of the tree. There are recursive and non-recursive ways to traverse the tree, and the non-recursive way can be divided into depth-first traversal and breadth-first traversal.
accomplish
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/rootView" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="10dp" android:background="#abcdef" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#156ec7" android:orientation="horizontal" android:padding="10dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="5dp" android:text="text1" android:textColor="#ffffff" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="5dp" android:text="text2" android:textColor="#ffffff" /> </LinearLayout> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button 1" /> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#5d9726" android:padding="10dp"> <Button android:id="@+id/btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="button 2" /> <TextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/btn" android:padding="5dp" android:text="text3" android:textColor="#ffffff" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/btn" android:layout_toRightOf="@id/tv" android:padding="5dp" android:text="text4" android:textColor="#ffffff" /> </RelativeLayout> </LinearLayout>
The interface effect and the corresponding tree structure are as follows:
The node type with color is viewGroup
layout | abstract tree structure |
Specific algorithm implementation
The following methods implement the traversal results of three methods, and readers can refer to them.
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate (savedInstanceState); setContentView(R.layout.activity_main); ViewGroup root = (ViewGroup) findViewById(R.id.rootView); travelTree3(root); } // recursively traverse the tree private void travelTree1(View root) { if (root instanceof ViewGroup) { int childCount = ((ViewGroup) root).getChildCount(); for (int i = 0; i < childCount; i++) { travelTree1(((ViewGroup) root).getChildAt(i)); } } else if (root instanceof View) { Log.i("visitView", root.toString()); if (root instanceof Button) root.setBackgroundColor(Color.parseColor("#ff0000")); } } //Non-recursive breadth traversal, using the queue data structure private void travelTree2(View root) { ArrayDeque queue = new ArrayDeque(); queue.addLast(root); while (!queue.isEmpty()) { // get the head of the team View front = (View) queue.getFirst(); //If it is viewGroup, make the child node into the queue if (front instanceof ViewGroup) { int childCount = ((ViewGroup) front).getChildCount(); for (int i = 0; i < childCount; i++) { queue.addLast(((ViewGroup) front).getChildAt(i)); } } //If the head of the queue is of View type, output else if (front instanceof View) Log.i("visitView", front.toString()); // The head of the team goes out of the queue queue.pollFirst(); } } //Non-recursive depth traversal, using stack data structure private void travelTree3(View root) { ArrayDeque stack = new ArrayDeque(); stack.addLast(root); while (!stack.isEmpty()) { // get the top of the stack View top = (View) stack.getLast(); // pop the stack stack.pollLast(); //If it is viewGroup, push the child node to the stack if (top instanceof ViewGroup) { int childCount = ((ViewGroup) top).getChildCount(); for (int i = childCount - 1; i >= 0; i--) { stack.addLast(((ViewGroup) top).getChildAt(i)); } } //If the top of the stack is a View type, output else if (top instanceof View) Log.i("visitView", top.toString()); } } }