Android custom view and custom attribute, android custom View

Source: Internet
Author: User
Tags xml attribute

Android custom view and custom attribute, android custom View

This is the content in Android UI Fundamentals.

Create a custom View

To create a custom UI component, you must first inherit a View class.
First, create a simple custom view to display a cross line.

The first thing to do is to create a CrossView class that inherits the View.

    public CrossView(Context context, AttributeSet attrs) {        super(context, attrs);    }

The second parameter of the constructor is used to pass XML parameters. We will discuss it later. Next we will rewrite two basic methods:onMeasureAndonDraw.

OnMeasure

System CallonMeasureMethod to determine the size of the view and its sub-view. The two parameter types areintBut these two parameters are not common numbers, but twoMeasureSpec,MeasureSpecIt is a combination of a pattern and an integer, which is implemented as an integer. The pattern value has the following situations:

Mode Explanation
UNSPECIFIED The parent view has no restrictions on this view. It can be of any size.
AT_MOST This view can be smaller than or equalMeasureSpecAny size of medium size
EXACTLY The parent view must beMeasureSpecSpecified size

When you create a custom view and override itonMeasureMethod, you must correctly handle each situation, get the corresponding size, and then mustonMeasureCallingsetMeasureDimensionsMethod, the parameter is the size you decide, if not called, an exception will be thrown.
Below is the rewriteonMeasureMethod code.

    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        setMeasuredDimension(calculateMeasure(widthMeasureSpec), calculateMeasure(heightMeasureSpec));    }

Note thatcalculateMeasureThe method is defined by ourselves. Next we will complete this method.
We first define a default size of 100, in the unit of dp (I'm not sure if it's dp.).

private static final int DEFAULT_SIZE = 100;

Multiply the pixel density of the device to obtain the actual displayed pixel value.

int result = (int) (DEFAULT_SIZE * getResources().getDisplayMetrics().density);

Then we need to get the mode and size from MeasureSpec.

int specMode = MeasureSpec.getMode(measureSpec);int specSize = MeasureSpec.getSize(measureSpec);

Next, based onspecModeTo determineresultWhat is the value.

  • MeasureSpec.UNSPECIFIED
    At this time, the parent control has no requirements on the size of the custom view, so I will use the default size as the result, that is
int result = (int) (DEFAULT_SIZE * getResources().getDisplayMetrics().density);
  • MeasureSpec.AT_MOST
    In this case, the parent control cannot exceed the specified size value. In this case, select the minimum value and the default value. In either case, this method is valid.
result = Math.min(specSize, result);
  • MeasureSpec.EXACTLY
    In this case, the parent control requires that the child view be of the given size.resultJust like it
result = specSize;

Based on the above discussion, our method code is as follows:

    private static final int DEFAULT_SIZE = 100;    private int calculateMeasure(int measureSpec) {        int result = (int) (DEFAULT_SIZE * getResources().getDisplayMetrics().density);        int specMode = MeasureSpec.getMode(measureSpec);        int specSize = MeasureSpec.getSize(measureSpec);        if (specMode == MeasureSpec.EXACTLY) {            result = specSize;        } else if (specMode == MeasureSpec.AT_MOST) {            result = Math.min(specSize, result);        }        return result;    }
OnDraw

It is called when the view should draw its contentonDrawMethod. CreatePaintObject, which handles things such as color and text size.
PassCrossViewTo createPaintObject

    private Paint mPaint;    public CrossView(Context context, AttributeSet attrs) {        super(context, attrs);        mPaint = new Paint();        mPaint.setAntiAlias(true);        mPaint.setColor(0xffff0000);    }

The above code is createdPaintObject, and set the anti-aliasing and color.
Next rewriteonDrawMethod. The template is as follows,canvas.save()Andcanvas.restore()I will not explain it, but it will not affect the subsequent understanding.

    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        canvas.save();        // code goes here        canvas.restore();    }

We scale the canvas Based on The View Size, so that we can use a floating point number between 0 and 1 as the coordinates of the draw line.

    private static final float[] mPoints = {0.5f, 0f,                                            0.5f, 1f,                                            0f, 0.5f,                                            1f, 0.5f};    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        canvas.save();        canvas.scale(getWidth(), getHeight());        canvas.drawLines(mPoints, mPaint);        canvas.restore();    }

We add our custom control to the xml of the activity.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:paddingTop="@dimen/activity_vertical_margin"    android:paddingBottom="@dimen/activity_vertical_margin"    tools:context=".MainActivity">    <com.shaw.uitest.CrossView        android:layout_width="wrap_content"        android:layout_height="wrap_content" />    <com.shaw.uitest.CrossView        android:layout_marginTop="10dp"        android:layout_width="wrap_content"        android:layout_height="wrap_content" /></LinearLayout>

Run the command to see the picture at the beginning of the article.

Add custom attributes to the custom View

With the custom view, we want it to be configured through the custom XML Attribute. To do this, we need to declare the attribute and then add a new namespace in the XML layout, finally, process the AttributeSet object that is passed to the custom view constructor.

Declare attributes

Create an attrs. xml file under the res/values/directory (which can be another name) and add the following content to it:

<?xml version="1.0" encoding="utf-8"?><resources>    <declare-styleable name="cross">        <attr name="android:color" />        <attr name="rotation" format="string" />    </declare-styleable></resources>

declare-styleableThe element has a name attribute used to reference custom attributes in the Code. Each custom attribute usesattrElement to declare,attrThe element has two attributes: name and format. name is used for reference and format represents its data type. If the default system attribute is used, format is not required, if you try to define a different format for an existing property, the project cannot be built. declared on the outer layerattrOtherdeclare-styleableReuse is the same as using system attributes, for example:

<?xml version="1.0" encoding="utf-8"?><resources>    <attr name="test" format="string" />    <declare-styleable name="foo">        <attr name="test" />    </declare-styleable>    <declare-styleable name="bar">        <attr name="test" />    </declare-styleable></resources>

You can also create custom values for attributes, such

<attr name="enum_attr">    <enum name="value1" value="1" />    <enum name="value2" value="2" /></attr><attr name="flag_attr">    <flag name="flag1" value="0x01" />    <flag name="flag2" value="0x02" /></attr>

enumAndflagAll must be integers. The difference is thatflagAvailable|For exampleandroid:gravityThe value is flag.

Use attributes in XML

To use new attributes in our XML, we must first declare the namespace for the view. In fact, we often see the namespace declaration. For example, we often see the namespace declaration in the xml file of the activity.

xmlns:android="http://schemas.android.com/apk/res/android"

This namespace declares all keywordsandroidAll attributes starting with android can be found in the android package. to use custom attributes, You need to declare a new namespace with the new package name. Next, add a new namespace for the CrossView attributes and add the relevant xml configuration in the Custom View:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    xmlns:crossview="http://schemas.android.com/apk/res-auto"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:paddingTop="@dimen/activity_vertical_margin"    android:paddingBottom="@dimen/activity_vertical_margin"    tools:context=".MainActivity">    <com.shaw.uitest.CrossView        android:layout_width="wrap_content"        android:layout_height="wrap_content"        crossview:rotation="30"        android:color="#ff0000ff"/>    <com.shaw.uitest.CrossView        android:layout_marginTop="10dp"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        crossview:rotation="50"        android:color="#ff00ff00"/></LinearLayout>

AllcrossviewAttributes starting with (name can use something else) can be found in res. This is the method required by Gradle.

Use XML attributes in code

InCrossViewThe constructorAttributeSetObject. You can use it to obtain the attributes declared in the XML layout.
UpdateCrossViewAnd add corresponding functions and member variables:

    private float mRotation;    public CrossView(Context context, AttributeSet attrs) {        super(context, attrs);        mPaint = new Paint();        mPaint.setAntiAlias(true);        TypedArray arr = getContext().obtainStyledAttributes(attrs, R.styleable.cross);        int color = arr.getColor(R.styleable.cross_android_color, Color.BLACK);        float rotation = arr.getFloat(R.styleable.cross_rotation, 0f);        arr.recycle();        setColor(color);        setRotation(rotation);    }    public void setColor(int color) {        mPaint.setColor(color);    }    public void setRotation(float degree) {        mRotation = degree;    }

Update simultaneouslyonDrawCode

    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        canvas.save();        canvas.scale(getWidth(), getHeight());        canvas.rotate(mRotation, 0.5f, 0.5f);        canvas.drawLines(mPoints, mPaint);        canvas.restore();    }

The center of our rotation is the center of the canvas, rather than the upper left corner.
Run the program as follows:

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.