Home>

Demand generation background:

Why introduce custom attributes?When the native properties provided by android cannot meet the actual needs,For example, we need to customize the circle percentage radius, the circle background, the position of the circle display, the background of the circle progress, and so on.This time we need our custom properties.

Custom property steps:1.) Add an attrs.xml file under the res/values ​​file, if the project is relatively large,Will cause the attrs.xml code to be quite large,At this time, you can name it according to the corresponding function module.Easy to find,For example:login module related attrs_login.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
 <declare-styleable name="roundimageview">
  <attr name="borderradius" />
  <attr name="type" />
 </declare-styleable>
</resources>

2.) How to declare a set of attributes

Use<declare-styleable name="percentview"></declare-styleable>to define a collection of attributes,name is the name of the property collection,The name must be known.

<declare-styleable name="percentview">
 <!-Add attribute->
 </declare-styleable>

Then we define the attribute value,Define the value of an attribute by<attr name="textcolor" />The name of the attribute must also be known.format indicates the type of the value of this attribute,There are the following types:

•reference:Reference resources

•string:string

•color:color

•boolean:boolean

•Dimension:size value

•float:floating point

•integer:integer

•fraction:percentage

•enum:enumeration type

•flag:bitwise OR operation

Based on the above requirements,We can define the percentage control properties

<declare-styleable name="percentview">
  <attr name="percent_circle_gravity"><!-The position where the circle is drawn->
   <flag name="left" value="0" />
   <flag name="top" value="1" />
   <flag name="center" value="2" />
   <flag name="right" value="3" />
   <flag name="bottom" value="4"/​​>
  </attr>
  <attr name="percent_circle_radius" /><!-Circle radius->
  <attr name="percent_circle_progress" /><!-Current progress value->
  <attr name="percent_progress_color" /><!-Progress display color->
  <attr name="percent_background_color" /><!-Circle background color->
 </declare-styleable>

3.) How to use in layout

<?xml version="1.0" encoding="utf-8"?>
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:lee="http://schemas.android.com/apk/res-auto"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical">
 <com.whoislcj.views.percentview
  android:layout_width="200dp"
  android:layout_height="200dp"
  android:layout_margin="10dp"
  android:background="@ color/red"
  android:padding="10dp"
  lee:percent_background_color="@ color/gray"
  lee:percent_circle_gravity="left"
  lee:percent_circle_progress="30"
  lee:percent_circle_radius="50dp"
  lee:percent_progress_color="@ color/blue" />
</linearlayout>

4.) How to get custom properties in custom controls

After compilation of each attribute set, there will be a styleable object. Typedarray is obtained through the styleable object, and then the attribute value is obtained through the key-value pair.This is similar to the method of sharedpreference.

typedarray typedarray=context.obtainstyledattributes (attrs, r.styleable.percentview);
 if (typedarray!=null) {
  backgroundcolor=typedarray.getcolor (r.styleable.percentview_percent_background_color, color.gray);
  progresscolor=typedarray.getcolor (r.styleable.percentview_percent_progress_color, color.blue);
  radius=typedarray.getdimension (r.styleable.percentview_percent_circle_radius, 0);
  progress=typedarray.getint (r.styleable.percentview_percent_circle_progress, 0);
  gravity=typedarray.getint (r.styleable.percentview_percent_circle_gravity, center);
  typedarray.recycle ();
  }

5.) Complete example

public class percentview extends view {
 private final static string tag=percentview.class.getsimplename ();
 private paint mpaint;
 private int backgroundcolor=color.gray;
 private int progresscolor=color.blue;
 private float radius;
 private int progress;
 private float centerx=0;
 private float centery=0;
 public static final int left=0;
 public static final int top=1;
 public static final int center=2;
 public static final int right=3;
 public static final int bottom=4;
 private int gravity=center;
 private rectf rectf;//The bounds of the shape and size of the arc used to define
 public percentview (context context) {
  super (context);
  init ();
 }
 public percentview (context context, attributeset attrs) {
  super (context, attrs);
  initparams (context, attrs);
  init ();
 }
 public percentview (context context, attributeset attrs, int defstyleattr) {
  super (context, attrs, defstyleattr);
  initparams (context, attrs);
  init ();
 }
 private void init () {
  mpaint=new paint ();
  mpaint.setantialias (true);
  rectf=new rectf ();
 }
 private void initparams (context context, attributeset attrs) {
  mpaint=new paint ();
  mpaint.setantialias (true);
  rectf=new rectf ();
  typedarray typedarray=context.obtainstyledattributes (attrs, r.styleable.percentview);
  if (typedarray!=null) {
   backgroundcolor=typedarray.getcolor (r.styleable.percentview_percent_background_color, color.gray);
   progresscolor=typedarray.getcolor (r.styleable.percentview_percent_progress_color, color.blue);
   radius=typedarray.getdimension (r.styleable.percentview_percent_circle_radius, 0);
   progress=typedarray.getint (r.styleable.percentview_percent_circle_progress, 0);
   gravity=typedarray.getint (r.styleable.percentview_percent_circle_gravity, center);
   typedarray.recycle ();
  }
 }
 @override
 protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {
  super.onmeasure (widthmeasurespec, heightmeasurespec);
  int widthmode=measurespec.getmode (widthmeasurespec);
  int widthsize=measurespec.getsize (widthmeasurespec);
  int heightmode=measurespec.getmode (heightmeasurespec);
  int heightsize=measurespec.getsize (heightmeasurespec);
  log.e (tag, "onmeasure--widthmode->" + widthmode);
  switch (widthmode) {
   case measurespec.exactly://
    break;
   case measurespec.at_most:
    break;
   case measurespec.unspecified:
    break;
  }
  log.e (tag, "onmeasure--widthsize->" + widthsize);
  log.e (tag, "onmeasure--heightmode->" + heightmode);
  log.e (tag, "onmeasure--heightsize->" + heightsize);
  int with=getwidth ();
  int height=getheight ();
  log.e (tag, "ondraw ---->" + with + "*" + height);
  centerx=with/2;
  centery=with/2;
  switch (gravity) {
   case left:
    centerx=radius + getpaddingleft ();
    break;
   case top:
    centery=radius + getpaddingtop ();
    break;
   case center:
    break;
   case right:
    centerx=with-radius-getpaddingright ();
    break;
   case bottom:
    centery=height-radius-getpaddingbottom ();
    break;
  }
  float left=centerx-radius;
  float top=centery-radius;
  float right=centerx + radius;
  float bottom=centery + radius;
  rectf.set (left, top, right, bottom);
 }
 @override
 protected void onlayout (boolean changed, int left, int top, int right, int bottom) {
  super.onlayout (changed, left, top, right, bottom);
  log.e (tag, "onlayout");
 }
 @override
 protected void ondraw (canvas canvas) {
  super.ondraw (canvas);
  mpaint.setcolor (backgroundcolor);
  //fill fill, stroke stroke, fill_and_stroke fill and stroke
  mpaint.setstyle (paint.style.fill_and_stroke);
  canvas.drawcircle (centerx, centery, radius, mpaint);
  mpaint.setcolor (progresscolor);
  double percent=progress * 1.0/100;
  int angle=(int) (percent * 360);
  canvas.drawarc (rectf, 270, angle, true, mpaint);//Draw arcs according to progress
 }
}

operation result:Two effects displayed according to different configurations

summary:

  • Previous Passing parameters when Angular page jumps
  • Next In-depth explanation of ES6's new features, default parameters and arrow functions