"Android App Development technology: User Interface" Custom view class design

Source: Internet
Author: User
Tags drawtext

Guo Xiaoxing
Weibo: Guo Xiaoxing's Sina Weibo
Email:[email protected]
Blog: http://blog.csdn.net/allenwells
Github:https://github.com/allenwells

A well-designed class is always similar, it uses an easy-to-use interface to encapsulate a particular function, it uses CPU and memory efficiently, and when we design the view class, we usually consider the following factors:

    • Follow Android Standard Rules
    • Provides custom style attribute values and can be recognized by Android XML layout.
    • Issue an accessible event
    • Different platforms compatible with Android

Let's show you how to implement a well-designed class step-by-step.

One inherits a view class

The view class in the Android framework inherits from view, and our custom view can inherit the view or other view's subclass directly. To enable ADT to recognize our view, we must provide at least one constructor, as follows:

class PieChart extends View {    publicPieChart(Context context, AttributeSet attrs) {        super(context, attrs);    }}
Two definition custom properties

In order to add a built-in view to the UI, we need to specify its style and behavior through XML attributes, good custom view can add and change styles through XML, in order to achieve this effect, we usually consider:

    • Define your own properties for a custom view under the Resource tab
    • Specifying attribute values in XML layout
    • Get property values at run time
    • Apply the acquired attribute value to a custom view

Define your own properties and add them to the Res/values/attrs.xml file as follows:

<resources>   <declare-styleable name="Piechart">       <attr name="Showtext" format="boolean" />       <attr name="labelposition" format="enum">           <enum name="Left" value="0"/>           <enum name="Right" value="1"/>       </attr>   </declare-styleable></Resources>

The above defines two custom properties: Showtext and LabelPosition, which belong to the styleable instance under the Piechat project, and the Styleable instance name usually matches the name of the custom view.

When we define our own properties, we can use them in the layout XML file, just like built-in properties, where the unique attribute does not belong to the namespace, as follows:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"   xmlns:custom="http://schemas.android.com/apk/res/com.example.customviews"><com.example.customviews.charting.PieChart     custom:showText="true"     custom:labelPosition="left" /></LinearLayout>

Note :

    1. To avoid entering long strings of namespace names, the example above uses the xmlns directive, which can be assigned custom as Http://schemas.android.com/apk/res/com.example.customviews The alias of the namespace. We can also use other aliases as namespace.
    2. If your view is a inner class, we need to specify the outer class for this view. Similarly, if Piechart has a inner class called Pieview. In order to use the properties that are set in this class, we need to use Com.example.customviews.charting.piechart$pieview.
Three-App custom properties

When view is created from XML layout, the attribute values under the XML tag are read from Res and passed to the view's constructor as a attributeset parameter, although the values can be read directly from the AttributeSet. But doing so has the following drawbacks:

    • The owning property resource has not been parsed
    • Styles does not apply on

The way we go through attrs is to get to the property value directly, but we can't determine the type of the value, as follows:

//通过此方法可以获取title的值,但是不知道它的类型,处理起来很容易出问题。String title = attrs.getAttributeValue(null"title");int resId = attrs.getAttributeResourceValue(null"title"0);title = context.getText(resId));

Instead, the Obtainstyledattributes () method is used to get the value of the property, which passes a Typedarray object, the android resource compiler to each of the RES directories, The auto-generated R.java file defines the array and constants that hold the property ID, which are used to refer to each property in the array. We can read these properties through the Typedarray object.

publicPieChart(Context context, AttributeSet attrs) {   super(context, attrs);   TypedArray a = context.getTheme().obtainStyledAttributes(        attrs,        R.styleable.PieChart,        00);   try {       false);       0);   finally {       a.recycle();   }}

Note : The Typedarray object is a shared object that should be recycled when it is finished.

Four Add properties and events

Attributes is a powerful way to control the behavior and appearance of the view, but it can only be read when the view is initialized, in order to provide a dynamic behavior, we need to set some set and get methods, as follows:

publicbooleanisShowText() {   return mShowText;}publicvoidsetShowText(boolean showText) {   mShowText = showText;   //invalidate()和requestLayout()两个方法的调用是确保稳定运行的关键。当   //View的某些内容发生变化的时候,需要调用invalidate来通知系统对这个View   //进行redraw,当某些元素变化会引起组件大小变化时,需要调用requestLayout   //方法。调用时若忘了这两个方法,将会导致hard-to-find bugs。   invalidate();   requestLayout();}

In addition to exposing properties, we also need to expose events, and custom view needs to be able to support listeners that respond to events.

Five drawing View appearance 5.1 overriding OnDraw () method 5.1.1 Creating a drawing object

The most important step in drawing a custom view's appearance is to override OnDraw (), the parameter of OnDraw () is a canvas object, and the canvas object defines methods for drawing text, lines, images, and many other graphics.

The OnDraw () method does the following common actions:

    • Draw text using DrawText (). Specifies the font to set the text color by calling Settypeface () and by SetColor ().
    • Draw basic graphics using DrawRect (), DrawOval (), DrawArc (). Use SetStyle () to specify whether the shape requires filled, outlined.
    • Draw some complex graphics, using the path class. Draw a graph by adding lines and curves to the Path object, and then using DrawPath (). As with the basic graphics. It's outlined, filled, both.
    • You define a gradient by creating a LinearGradient object. Call Setshader () to use LinearGradient.
    • Draw a picture by using Drawbitmap.

Example

protected void OnDraw(Canvas canvas) {Super. OnDraw (canvas);//Draw the shadowCanvas.drawoval (Mshadowbounds, mshadowpaint);//Draw the label textCanvas.drawtext (Mdata.get (Mcurrentitem) Mlabel, Mtextx, Mtexty, Mtextpaint);//Draw the pie slices    for(inti =0; I < mdata.size ();       ++i) {Item it = mdata.get (i);       Mpiepaint.setshader (It.mshader); Canvas.drawarc (Mbounds, the-It.mendangle, It.mendangle-it.mstartangle,true, Mpiepaint); }//Draw the pointerCanvas.drawline (MTEXTX, Mpointery, Mpointerx, Mpointery, Mtextpaint); Canvas.drawcircle (Mpointerx, Mpointery, Mpointersize, mtextpaint);}

The Android Graphics framework defines the drawing as the following two classes:

    • Canvas: What to draw
    • Paint: How to draw

Example

Create Paint objects, define colors, styles, fonts, and so on.

private  void  init  () {mtextpaint = new  Paint (paint.anti _alias_flag); Mtextpaint.setcolor (Mtextcolor); if  (Mtextheight = = 0 ) {mtextheight = Mtextpaint.gettextsize (); } else  {mtextpaint.settextsize (mtextheight); } mpiepaint = new  Paint (Paint.anti_alias_flag); Mpiepaint.setstyle (Paint.Style.FILL); Mpiepaint.settextsize (Mtextheight); Mshadowpaint = new  Paint (0 ); Mshadowpaint.setcolor (0xff101010 ); Mshadowpaint.setmaskfilter (new  blurmaskfilter (8 , BlurMaskFilter.Blur.NORMAL)); 
5.1.2 Handling Layout Events

In order to draw the custom view correctly, we need to know the size of the view. Complex custom view often needs to perform multiple layout calculations based on the size and shape on the screen. Instead of assuming this view is displayed on the screen size. Even if only one program uses a custom view, it still needs to deal with the effects of different screen sizes, different densities, and different orientations.

There are many ways to calculate the size of a view.

    • Onsizechanged ()

Onsizechanged (): When the view is first given a size, or if the size of the view is changed, we can calculate the position, spacing, and other view size values in the method.

When our view is set to size, the layout manager assumes that this size includes all of the view's padding (Padding), and when we calculate the size of the view, we need to handle the value of the padding as follows:

// Account for paddingfloat xpad = (float)(getPaddingLeft() + getPaddingRight());float ypad = (float)(getPaddingTop() + getPaddingBottom());// Account for the labelif (mShowText) xpad += mTextWidth;float ww = (float)w - xpad;float hh = (float)h - ypad;// Figure out how big we can make the pie.float diameter = Math.min(ww, hh);
    • Onmeasure ()

The Onmeasure () method is used to precisely control the size of the view, and the parameter of the method is View.meaurespec, which tells us the size of the parent control of the view.

@Overrideprotected void onmeasure(intWidthmeasurespec,intHEIGHTMEASURESPEC) {//Try for a width based in our minimum   intMINW = Getpaddingleft () + getpaddingright () + getsuggestedminimumwidth ();intW = resolvesizeandstate (MINW, Widthmeasurespec,1);//Whatever The width ends up being, ask for a height, this would let the pie   //Get as big as it can   intMinh = Measurespec.getsize (w)-(int) Mtextwidth + getpaddingbottom () + getpaddingtop ();inth = resolvesizeandstate (Measurespec.getsize (w)-(int) Mtextwidth, Heightmeasurespec,0); Setmeasureddimension (W, h);}

Note :

    • The process of calculation takes into account the padding of the view. This will be mentioned later in this section, which is controlled by view.
    • The Help Method Resolvesizeandstate () is used to create the final width-height value. This method returns a suitable View.measurespec value and passes it to the Onmeasure method by comparing the demand size of the view with the spec value.
    • Onmeasure () has no return value. It gets the result by calling Setmeasureddimension (). Calling this method is mandatory, and if we omit this method, a run-time exception occurs.
Six-process input gestures

Android provides a model of input events, the user's actions are converted to events that trigger some callback functions, and we can override these callback methods to handle the user's hungry input events.

Common user input events are touch events, and the interaction between multiple touch events is called gesture, and common gesture are as follows:

    • Tapping
    • Pulling
    • Flinging
    • Zooming

Gesturedetector is used to manage gesture, It is built through the incoming Gesturedetector.ongesturelistener, and if we just want to handle a few simple gesture manipulations, we can also pass in Gesturedetector.simpleongesturelistener as follows:

class mListener extends GestureDetector.SimpleOnGestureListener {   @Override   publicbooleanonDown(MotionEvent e) {       returntrue;   new GestureDetector(PieChart.thisnew mListener());

Regardless of whether we use Gesturedetector.simpleongesturelistener, we always have to implement the Ondown () method and return True. Because all the gestures start from Ondown (). If you return False in Ondown (), the system will assume that we want to ignore the subsequent gesture, then Gesturedetector.ongesturelistener's other callback methods will not be executed.

Once we have implemented Gesturedetector.ongesturelistener and created an instance of Gesturedetector, We can use our gesturedetector to stop the touch events you receive in Ontouchevent as follows:

@OverridepublicbooleanonTouchEvent(MotionEvent event) {   boolean result = mDetector.onTouchEvent(event);   if (!result) {       if (event.getAction() == MotionEvent.ACTION_UP) {           stopScrolling();           true;       }   }   return result;}
Seven optimized view performance 7.1 improve method efficiency

In order to design a good view, our view should be able to execute faster, no lag, and the animation should remain at 60fps. In order to speed up our view, for frequently called methods, we should try to reduce unnecessary methods, in the initialization or animation gap to do the memory mismatch work.

Let's talk about how to improve the efficiency of some common methods.

    • OnDraw () method

OnDraw () method, we should minimize the call of the OnDraw () method, also called the Invalidate () method, and if there is a need to call the invalidate () method, you should also call the Invalidate () method with parameters for precise drawing, Instead of the invalidate () method without parameters, because the invalidate () method without parameters draws the entire view.

    • Requestlayout () method

The Requestlayout () method will allow the Android UI system to traverse the entire view hierarchy to calculate the size of each view. If a conflicting value is found, it will need to be recalculated several times. In addition, it is necessary to keep the view level flat, which helps to improve the efficiency. To design a complex UI, we should consider writing a custom viewgroup to perform its layout operations. Unlike the built-in view, a custom view allows the program to measure only this part, which avoids traversing the entire view hierarchy to calculate the size.

7.2 Using hardware acceleration

Starting with Android 3.0, Android's 2D image system can be accelerated via the GPU (graphics processing Unit). GPU hardware acceleration can improve the performance of many programs. But that's not to say it fits all programs. The Android framework gives us the freedom to control whether hardware acceleration is enabled for each part of your program.

Once you turn on hardware acceleration, the performance hints are not necessarily noticeable. The GPU for mobile devices is performing well in some operations, such as scaling,rotating and translating. But for some other tasks, such as drawing straight lines or curves, the performance is poor. To get the most out of GPU acceleration, we should maximize the number of operations that the GPU excels at, minimizing the number of operations the GPU is not good at.

Example

Pie is relatively time-consuming to draw. The solution is to put the pie in a sub-view and set the view to use Layer_type_hardware for acceleration.

Private  class pieview extends View {        Public Pieview(Context context) {Super(context);if(!isineditmode ()) {Setlayertype (View.layer_type_hardware,NULL); }       }@Override       protected void OnDraw(Canvas canvas) {Super. OnDraw (canvas); for(Item It:mdata)               {Mpiepaint.setshader (It.mshader); Canvas.drawarc (Mbounds, the-It.mendangle, It.mendangle-it.mstartangle,true, Mpiepaint); }       }@Override       protected void onsizechanged(intWintHintOLDW,intOLDH) {mbounds =NewRECTF (0,0, W, h);   } RECTF Mbounds; }

Copyright NOTICE: When we seriously to do one thing, we can find the endless fun, colorful technology like the scenery on the road, while walking to appreciate.

"Android App Development technology: User Interface" Custom view class design

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.