How to customize viewgroup

Source: Internet
Author: User

During development, there are sometimes some requirements. Simply using the layout and controls provided by the system does not meet our development needs. Therefore, you can customize the layout (viewgroup) by yourself) and controls (view. Here, I will use a simple example to explain the basic process of custom viewgroup, hoping to help those who do not know the process.

First, we want to implement the following layout:


This looks very simple. You can achieve this by using the layout provided by the system. You do not need to customize the viewgroup !!! However, if you try to use the system layout, you will find some problems. Problem 1: To achieve different view staggered effects, you must set different fixed margin parameters for them. The possible problem is that different mobile phones may have different display effects, that is, adaptation issues! Question 2: If you want to add more views, you also need to calculate the margin parameter of each view. This is very difficult. Besides, here we will mainly explain the basic process of custom viewgroup, therefore, the simpler the example, the better understanding!

First, we can customize the attributes we want for our viewgroup. Here I have defined two attributes for viewgroup: horizontal_spacing (horizontal spacing of views in the layout) vertical_spacing and vertical_spacing. In addition, layout_vertical_spacing is also defined, which can be used by the view in our custom viewgroup.

Content of attrs. xml:

<?xml version="1.0" encoding="utf-8"?><resources>    <declare-styleable name="MyCustomLayout">        <attr name="horizontal_spacing" format="dimension" />        <attr name="vertical_spacing" format="dimension" />    </declare-styleable>    <declare-styleable name="MyCustomLayout_LayoutParams">        <attr name="layout_vertical_spacing" format="dimension" />    </declare-styleable></resources>

Define the default values of two attributes in dimens. xml.

Dimens. XML content:

<?xml version="1.0" encoding="utf-8"?><resources>    <dimen name="horizontal_spacing">10dp</dimen>    <dimen name="vertical_spacing">10dp</dimen></resources>

Next, the most important step is coming. Let's take a look at our custom viewgroup.

The following is the source code:

package com.customlayout.mycustomlayout;import android.content.Context;import android.content.res.TypedArray;import android.util.AttributeSet;import android.view.View;import android.view.ViewGroup;public class MyCustomLayout extends ViewGroup {    private int mHorizontalSpacing;    private int mVerticalSpacing;    public MyCustomLayout(Context context, AttributeSet attrs) {        super(context, attrs);        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyCustomLayout);        mHorizontalSpacing = ta.getDimensionPixelSize(R.styleable.MyCustomLayout_horizontal_spacing,                getResources().getDimensionPixelSize(R.dimen.horizontal_spacing));        mVerticalSpacing = ta.getDimensionPixelSize(R.styleable.MyCustomLayout_vertical_spacing,                getResources().getDimensionPixelSize(R.dimen.vertical_spacing));        ta.recycle();    }    @Override    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {        // TODO Auto-generated method stub        return p != null;    }    @Override    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {        // TODO Auto-generated method stub        return (LayoutParams) p;    }    @Override    public LayoutParams generateLayoutParams(AttributeSet attrs) {        return new LayoutParams(getContext(), attrs);    }    @Override    protected LayoutParams generateDefaultLayoutParams() {        return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        int width = 0;        int height = getPaddingTop();        int verticalSpacing;        final int count = getChildCount();        for (int i = 0; i < count; i++) {            View child = getChildAt(i);            measureChild(child, widthMeasureSpec, heightMeasureSpec);            verticalSpacing = mVerticalSpacing;            LayoutParams lp = (LayoutParams) child.getLayoutParams();            if (lp.verticalSpacing > 0) {                verticalSpacing += lp.verticalSpacing;            }            width = getPaddingLeft() + mHorizontalSpacing * i;            lp.x = width;            lp.y = height;            width += child.getMeasuredWidth();            height += verticalSpacing;        }        width += getPaddingRight();        height += getChildAt(getChildCount() - 1).getMeasuredHeight() + getPaddingBottom();        setMeasuredDimension(resolveSize(width, widthMeasureSpec),                resolveSize(height, heightMeasureSpec));    }    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        final int count = getChildCount();        for (int i = 0; i < count; i++) {            View child = getChildAt(i);            LayoutParams lp = (LayoutParams) child.getLayoutParams();            child.layout(lp.x, lp.y, lp.x + child.getMeasuredWidth(), lp.y + child.getMeasuredHeight());        }    }    public static class LayoutParams extends ViewGroup.LayoutParams {        public int x;        public int y;        public int verticalSpacing;        public LayoutParams(Context c, AttributeSet attrs) {            super(c, attrs);            TypedArray ta = c.obtainStyledAttributes(attrs, R.styleable.MyCustomLayout_LayoutParams);            verticalSpacing = ta.getDimensionPixelSize(R.styleable.MyCustomLayout_LayoutParams_layout_vertical_spacing, -1);            ta.recycle();        }        public LayoutParams(int w, int h) {            super(w, h);        }    }}
First, let's start with the mycustomlayout. Java constructor.

public MyCustomLayout(Context context, AttributeSet attrs) {        super(context, attrs);        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyCustomLayout);        mHorizontalSpacing = ta.getDimensionPixelSize(R.styleable.MyCustomLayout_horizontal_spacing,                getResources().getDimensionPixelSize(R.dimen.horizontal_spacing));        mVerticalSpacing = ta.getDimensionPixelSize(R.styleable.MyCustomLayout_vertical_spacing,                getResources().getDimensionPixelSize(R.dimen.vertical_spacing));        ta.recycle();    }
The constructor has two parameters. attrs is the property set of our layout. With this parameter, we can get the relevant attributes set in the XML file of the layout.

Next, let's talk about the onmeasure method. As the name suggests, this method is a measurement method. Its function is to traverse every view in the layout and measure every view (call the measurechild method ), then set layoutparams for the view, and set the view location, that is, the X and Y coordinates on the screen, for use in the onlayout method. Here, layoutparams is rewritten, where int X and INT y Save the coordinates of the view in the layout.Note: When you override the layoutparams class, you must perform checklayoutparams (viewgroup. layoutparams P), generatelayoutparams (viewgroup. layoutparams P), generatelayoutparams (attributeset attrs), and generatedefaultlayoutparams () are rewritten. Otherwise, an exception will occur !!!

Next, let's talk about the onlayout method. This method is to deploy all views in the layout. You can see from the method body that it uses a traversal to call the layout method for location deployment for each view in the layout.


Now, let's summarize the following:In a custom viewgroup process, the onmeasure and onlayout methods are overwritten. Onmeasure measures the size of each view and calculates the layout parameters by traversing the view in the layout. Onlayout is to traverse the view in the layout and arrange the position of each view.

Use our custom viewgroup in activity_main.xml:

<com.customlayout.mycustomlayout.MyCustomLayout    xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:customLayout="http://schemas.android.com/apk/res-auto"    android:id="@+id/layout"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:background="@android:color/white"    customLayout:horizontal_spacing="65dp"    customLayout:vertical_spacing="85dp">    <View        android:layout_width="100dp"        android:layout_height="150dp"        android:background="#00ff00" />    <View        android:layout_width="100dp"        android:layout_height="150dp"        android:background="#0000ff" />    <View        android:layout_width="100dp"        android:layout_height="150dp"        android:background="#ff0000" />    <View        android:layout_width="100dp"        android:layout_height="150dp"        android:background="#0ff000" />    <View        android:layout_width="100dp"        android:layout_height="150dp"        android:background="#00f0f0" /></com.customlayout.mycustomlayout.MyCustomLayout>


Source code of mainactivity. Java:

package com.customlayout.mycustomlayout;import android.app.Activity;import android.graphics.RectF;import android.os.Bundle;import android.view.animation.AlphaAnimation;import android.view.animation.Animation;import android.view.animation.AnimationSet;import android.view.animation.BounceInterpolator;import android.view.animation.LayoutAnimationController;import android.view.animation.TranslateAnimation;public class MainActivity extends Activity {    MyCustomLayout layout;    LayoutAnimationController layoutAnimationController;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        layout = (MyCustomLayout) findViewById(R.id.layout);        AnimationSet set = new AnimationSet(true);        AlphaAnimation a = new AlphaAnimation(0f, 1f);        a.setDuration(500);        TranslateAnimation t = new TranslateAnimation(Animation.RELATIVE_TO_SELF, -1f,                Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, 0f);        t.setDuration(500);        set.addAnimation(t);        set.addAnimation(a);        layoutAnimationController = new LayoutAnimationController(set);        layout.setLayoutAnimation(layoutAnimationController);    }}

Finally, let's talk about layout animation. In the viewgroup class, there is a property called layoutanimation, which is also called layout animation. If we specify an animation for this property, in this case, each of the viewgroup objects can be animated in the layout. In the oncreate () method above, I specified an animation set and set it to my custom mycustomlayout. After running the program, we can see that every view in mycustomlayout will appear in order with the animation I specified in mycustomlayout. The effect is cool!

In combination with this simple example, we will briefly introduce the method for customizing viewgroup. In other complex la s we use, we have implemented them using the method described above, however, their computation will be much more complex than the above example, but the basic principle is the same.

How to customize viewgroup

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.