ANDROID custom view-similar waterfall layout (with source code), android waterfall

Source: Internet
Author: User

ANDROID custom view-similar waterfall layout (with source code), android waterfall

Reprint please indicate this article from the blog of the big glutinous rice (http://blog.csdn.net/a396901990), thank you for your support!


Introduction:


In the custom view, it is actually very simple. You only need to know the three steps:

1. Measurement -- onMeasure (): Determines the size of the View.

2. Layout -- onLayout ():Determine the position of the View in the ViewGroup

3. Draw -- onDraw ():How to draw this View.


The onDraw System in step 1 has been well encapsulated, so we don't have to worry about it. We just need to focus on Step 1 and step 2.

Step 1MeasurementFor details, refer to: (ANDROID custom view-onMeasure, MeasureSpec source code process)

Step 2LayoutFor details, refer to: (ANDROID custom view-onLayout source code process)


The following describes how to use onMeasure and onLayout to customize a waterfall-like custom view.


:





The first gif is displayed on the mobile phone simulator. Because the mobile phone screen is small, one line is displayed in the vertical state, and two lines are displayed in the horizontal screen. Because the screen is large on the tablet, you can adjust the number of views displayed on each line based on the specific size and needs.

This example is just a simple display, but here we can regard each view as a Card. Each Card uses a fragment control, so that more Fragment can be displayed on a large screen as needed, so that you do not need to slide left or right in the ViewPager to display the fragment.



Code Analysis:


Main Activity:

    @Override    protected void onCreate( Bundle savedInstanceState )    {        super.onCreate(savedInstanceState);        setContentView(R.layout.main_layout);    }


Main_layout.xml:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:auto="http://schemas.android.com/apk/res-auto"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical">    <com.gxy.autolayout.MyScrollView        auto:columns="1"        android:id="@+id/myScrollView"        android:layout_margin="5dip"        android:layout_width="match_parent"        android:layout_height="match_parent">        </com.gxy.autolayout.MyScrollView></LinearLayout>
Nothing special, just adding a custom View in a LinearLayout -- MyScrollView. In addition, this View has a custom attribute. Columns, Which indicates how many views are displayed in each row. There are a lot of Custom Attributes online, so I will not waste time here.


MyScrollView:

/*** This class inherits from ScrollView to slide our custom view */public class MyScrollView extends ScrollView {int columns = 0; public MyScrollView (Context context) {super (context);} public MyScrollView (Context context, AttributeSet attrs) {super (context, attrs); // retrieves the custom attribute TypedArray typedArray = context in the layout. obtainStyledAttributes (attrs, R. styleable. myScrollView); columns = typedArray. getInteger (R. styleable. myScrollView_columns, 0); typedArray. recycle (); // initialize the initView (columns);} private void initView (int columns) {// create a LinearLayout as the top-level view of ScrollView (because ScrollView can only have one ViewGroup) LinearLayout linearLayout = new LinearLayout (getContext (); linearLayout. setOrientation (LinearLayout. VERTICAL); // Add a custom view AutoCardLayout in LinearLayout (all our logic is in this custom View class) linearLayout. addView (new AutoCardLayout (getContext (), columns); addView (linearLayout, new ViewGroup. layoutParams (ViewGroup. layoutParams. MATCH_PARENT, ViewGroup. layoutParams. MATCH_PARENT ));}}

AutoCardLayout:

/*** AutoCardLayout inherits from ViewGroup, the main function is to dynamically arrange each card view */public class AutoCardLayout extends ViewGroup according to the column value {// The number of columns displayed in each row int column = 0; // The horizontal spacing of each Card int margin = 20; // Add five predefined la s to the constructor (for the convenience of the graph, you can directly throw the constructor) public AutoCardLayout (Context context, int columns) {super (context); this. column = columns; View v1 = LayoutInflater. from (context ). inflate (R. layout. card_layout1, null); View v2 = LayoutInflater. from (context ). inflate (R. layout. card_layout2, null); View v3 = LayoutInflater. from (context ). inflate (R. layout. card_layout3, null); View v4 = LayoutInflater. from (context ). inflate (R. layout. card_layout4, null); View v5 = LayoutInflater. from (context ). inflate (R. layout. card_layout5, null); addView (v1, new LayoutParams (LayoutParams. MATCH_PARENT, LayoutParams. MATCH_PARENT); addView (v2, new LayoutParams (LayoutParams. MATCH_PARENT, LayoutParams. MATCH_PARENT); addView (v3, new LayoutParams (LayoutParams. MATCH_PARENT, LayoutParams. MATCH_PARENT); addView (v4, new LayoutParams (LayoutParams. MATCH_PARENT, LayoutParams. MATCH_PARENT); addView (v5, new LayoutParams (LayoutParams. MATCH_PARENT, LayoutParams. MATCH_PARENT);} // Override onMeasure method @ Override protected void onMeasure (int widthMeasureSpec, int evaluate) {}// Override onLayout method @ Override protected void onLayout (boolean changed, int l, int t, int r, int B ){}}
OnMeasure and onLayout are the focus of this article.

However, for better understanding, I will first explain the ideas:

1. This layout is similar to the waterfall layout. It is sorted from left to right, but will be re-aligned to bottom by column (this is very important to align by column)

2. In the onMeasure method, you must measure the width of each sub-View. The width of each sub-View should be the same, and it is related to the number of columns displayed in each row and the spacing.

3. In the onMeasure method, we cannot measure the measurement height of each sub-View (MeasureSpec. getSize (heightMeasureSpec) = 0) because the height in the ScrollView is uncertain (personally, I want to correct it)

4. In the onMeasure method, you need to measure the size of the parent View, and the width is determined. This mainly measures the actual height (the parent View height is the sum of the heights of the longest column sub-View)

5. In the onLayout method, layout should be performed based on the location of each View


OnMeasure

// Override onMeasure method @ Override protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {// obtain the actual measurement width of the parent View, int width = MeasureSpec. getSize (widthMeasureSpec); // (width-(column-1) * margin)/column to get the width of each sub-View (idea: parent View minus all spacing and then divide by the number of columns) // determine the detailed measurement width of the sub-View based on the sub-View width and Measurement Mode. int colWidthSpec = MeasureSpec. makeMeasureSpec (width-(column-1) * margin)/column, MeasureSpec. EXACTLY); // because no measurement is available View height, so the measurement mode is set here to get detailed measurement height int colHeightSpec = MeasureSpec. makeMeasureSpec (0, MeasureSpec. UNSPECIFIED); // array of columns, representing the height of all views in this column. int [] colPosition = new int [column]; // loop all subviews for (int I = 0; I <getChildCount (); I ++) {View child = getChildAt (I); // call the measure method of the sub-View and pass in the previously calculated value to measure the child. measure (colWidthSpec, colHeightSpec); // (I + 1 + column) % column this code is used to calculate the number of columns in the current View and the number of columns. Umn value is to prevent the remainder from being less than the remainder) // Add the height of the child View of the corresponding column colPosition [(I + 1 + column) % column] + = child. getMeasuredHeight () ;}// length of the parent View: int height = 0; // the following code calculates the value of the longest column in the array, the maximum column value is the height of the parent View for (int j = 0; j <column; j ++) {height = colPosition [j]> height? ColPosition [j]: height;} // measure the parent View setMeasuredDimension (width, height) based on the calculated high value of width );}

OnLayout

// Override onLayout method @ Override protected void onLayout (boolean changed, int l, int t, int r, int B) {// array of columns, int [] colPosition = new int [column] of all views in this column; // loop all subviews for (int I = 0; I <getChildCount (); I ++) {View child = getChildAt (I); // obtain the width and height of the sub-View, int width = child. getMeasuredWidth (); int height = child. getMeasuredHeight (); // obtain the subscript of the current View in the array of columns (if the remainder is 0, it is the last column) int index = (I + 1 + column) % c Olumn = 0? Column-1: (I + 1 + column) % column-1; // Add the height of the sub-View to the column height. colPosition [index] + = height; // calculate the upper-left and lower-right values of the current View and pass in the layout method for layout. // specific ideas I mentioned in the previous article about onlayout, you can determine the right and bottom values (right = left + width, bottom = top + height) as long as you know the left and top values and the width and height values of the sub-View) int left = l + index * (width + margin); int right = column = index + 1? R: left + width; int top = t + colPosition [index]-height; int bottom = top + height; child. layout (left, top, right, bottom );}}

OnMeasure and onLayout have been introduced. I think this algorithm is still very good.


The following describes my skills in customizing a View:

1. hierarchyviewer

2. DEBUG + find a sheet of paper and calculate it with pen


Hierarchyviewer

Needless to say, the artifacts for custom views

You can find it in the following directory:Your sdk path \ sdk \ tools

Here are some hierarchyviewer images. By the way, let's take a look at the view structure of this example:


Outermost layer structure



, Each sub-view is above the FrameLayout view, otherwise it cannot be correctly measured (for any reason, please advise ).

I wrote FrameLayout in each Cardlayout for convenience. In fact, it is better to add a new FrameLayout in the code and then addView (fragment is often wrapped in a FrameLayout when I look at the code, the truth should be the same ).



You can also click to view detailed proportions

You can also click the Profile Node in the upper-right corner to View the execution efficiency of the View (the three dots above the View are ).

Hierarchyviewer can also view detailed screen information, which can be used to detect pixel-level problems.

If you look at a complicated code, you can use hierarchyviewer to quickly understand the view structure.


DEBUG + find a sheet of paper and calculate it with pen:

The main function of hierarchyviewer is to call errors, while the specific width and height calculation still needs to keep track of debug, algorithms and ideas need to be designed and computed using paper and pen (unless you have a powerful brain)


Summary:

When I wrote onMeasure and onLayout, I wanted to write a small example. I planned to write a FlowLayout (Stream layout) example. However, someone just wrote one in the past few weeks, so I wrote it through the stream Layout idea. After writing it, I found that this is not the Waterfall Layout (Waterfall Layout.

There are many improvements in this example. For example, you cannot dynamically add or delete views or set column values. The view for each Card is not scaled in or out based on the screen size. The Card View should also be added to the Fragment and added to the custom View. I will make some improvements later.



If someone wants to download it, let's just look at the logic. I just made some CardLayout out from the east to the west, and the code in it was simply ignored.

In addition, this project is created by eclipse and then imported to Android Studio. Normal import is okay. If there is a problem, try to delete the build. gradle and other files before importing them. It is really difficult to create a project and copy several key classes...


Click to download the code




Who makes a Dialog with a grid view in android?

Dialog, you can customize a nine-Cell Layout, rewrite the Dialog, and bind the layout with inflater. I have a copy of the source code. If LZ wants it, provide an email.

Android mobile phone layout. How do I set controls for this screening layout? New users

Just remove the previous circle with two Radio.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.