Example tutorials for customizing view views in Android apps _android

Source: Internet
Author: User
Tags drawtext getcolor stringbuffer

First, the basis
a lot of Android Getting Started program apes may be more fearful about Android custom view, but this is the only way to get to the master's level, all ready to spend some time on custom view and write more articles. To summarize the steps for customizing the view first:
1. Customize View Properties
2, in the view of the construction method to get our custom attributes
3. Rewrite onmesure
4. Rewrite OnDraw
I marked 3 with [], so saying 3 is not necessarily necessary, but in most cases it needs to be rewritten.

1. Custom View properties, first create a attrs.xml under res/values/, define our attributes inside and declare our entire style.

<?xml version= "1.0" encoding= "Utf-8"?> 
<resources> 
 
  <attr name= "TitleText" format= "string"/ > 
  <attr name= "titletextcolor" format= "color"/> <attr name= 
  "titletextsize" format= "Dimension"/ > 
 
  <declare-styleable name= "Customtitleview" > 
    <attr name= "TitleText"/> <attr name= 
    " Titletextcolor "/> 
    <attr name= titletextsize"/> 
  </declare-styleable> 
 
</resources > 


We have defined the font, font color, font size 3 attributes, format is the value of this property type:
Altogether have: string,color,demension,integer,enum,reference,float,boolean,fraction,flag; not clear to Google.
And then declare our custom view in the layout.

<relativelayout xmlns:android= "http://schemas.android.com/apk/res/android" 
  xmlns:tools= "http:// Schemas.android.com/tools " 
  xmlns:custom=" http://schemas.android.com/apk/res/com.example.customview01 
  " Android:layout_width= "Match_parent" 
  android:layout_height= "match_parent" > 
 
  < Com.example.customview01.view.CustomTitleView 
    android:layout_width= "200DP" 
    android:layout_height= " 100DP " 
    custom:titletext=" 3712 " 
    custom:titletextcolor=" #ff0000 " 
    custom:titletextsize=" 40sp "/> 
 
</RelativeLayout> 

Be sure to introduce the xmlns:custom= "http://schemas.android.com/apk/res/com.example.customview01" to our namespace, and the following package path refers to the project's package

2, in the view of the construction method, get our custom style

/** * Text/private String mtitletext; 
  /** * Text color * * private int mtitletextcolor; 
 
  /** * Text Size * * private int mtitletextsize; 
  /** * When drawing Control of the scope of text drawing * * Private Rect Mbound; 
 
  Private Paint Mpaint; 
  Public Customtitleview (context, AttributeSet attrs) {This (context, attrs, 0); 
  The public Customtitleview {This (context, NULL); /** * get my custom style attributes * * @param context * @param attrs * @param defstyle * * * Public CUSTOMTI 
    Tleview (context, AttributeSet attrs, int defstyle) {Super (context, attrs, Defstyle); /** * Get the Custom style attribute we defined/TypedArray a = Context.gettheme (). Obtainstyledattributes (Attrs, R.styleable.cust 
    Omtitleview, Defstyle, 0); 
    int n = a.getindexcount (); 
      for (int i = 0; i < n; i++) {int attr = A.getindex (i); Switch (attr) {case R.styleable.customtitleview_titletext: 
        Mtitletext = a.getstring (attr); 
      Break Case R.styleable.customtitleview_titletextcolor://Default color set to Black Mtitletextcolor = A.getcolor (attr, color.b 
        LACK); 
      Break Case R.styleable.customtitleview_titletextsize://The default setting is 16sp,typevalue can also convert sp to px mtitletextsize = A.get Dimensionpixelsize (attr, (int) typedvalue.applydimension (typedvalue.complex_unit_sp, Getresources (). GetD 
        Isplaymetrics ())); 
 
      Break 
 
    } a.recycle (); 
    /** * Obtains the width and height of the drawn text/mpaint = new Paint (); 
    Mpaint.settextsize (mtitletextsize); 
    Mpaint.setcolor (Mtitletextcolor); 
    Mbound = new Rect (); 
 
  Mpaint.gettextbounds (mtitletext, 0, Mtitletext.length (), mbound); 
 }

We've rewritten 3 construction methods, the default layout file calls the construction of two parameters, so remember to let all the constructs call our three-parameter constructs, and we get our custom properties in the construction of three parameters.
3, we rewrite the ondraw,onmesure call system provided:

@Override 
  protected void onmeasure (int widthmeasurespec, int heightmeasurespec) 
  { 
    super.onmeasure ( Widthmeasurespec, Heightmeasurespec); 
 
  @Override 
  protected void OnDraw (Canvas Canvas) 
  { 
    mpaint.setcolor (color.yellow); 
    Canvas.drawrect (0, 0, getmeasuredwidth (), Getmeasuredheight (), mpaint); 
 
    Mpaint.setcolor (Mtitletextcolor); 
    Canvas.drawtext (Mtitletext, getwidth ()/2-mbound.width ()/2, GetHeight ()/2 + mbound.height ()/2, mpaint); 
   

The effect at this point is:

is not a good feeling, basically has implemented a custom view. But at this point, if we write the width and height of the layout file as Wrap_content, we will find that the effect is not our expectation:

The

System helps us measure the height and width is match_parnet, when we set the clear width and height, the system helps us to measure the result is the result we set, when we set to Wrap_content, or Match_ The parent system helps us measure the result is the length of the match_parent.
So, when Wrap_content is set, we need to measure ourselves, that is, to override the Onmesure method ":
to understand the specmode of measurespec before rewriting, altogether three types:
Exactly: generally set a definite value or match_parent
At_most: Indicates that the child layout is restricted to a maximum value, typically warp_content
UNSPECIFIED: Indicates how large the child layout wants, and rarely uses
Here is our rewrite Onmeasure code:

@Override protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {int widthmode = Measurespec.getmod 
  E (WIDTHMEASURESPEC); 
  int widthsize = measurespec.getsize (Widthmeasurespec); 
  int heightmode = Measurespec.getmode (Heightmeasurespec); 
  int heightsize = measurespec.getsize (Heightmeasurespec); 
  int width; 
  int height; 
  if (Widthmode = = measurespec.exactly) {width = widthsize; 
    else {mpaint.settextsize (mtitletextsize); 
    Mpaint.gettextbounds (mtitle, 0, Mtitle.length (), mbounds); 
    float textWidth = Mbounds.width (); 
    int desired = (int) (Getpaddingleft () + TextWidth + getpaddingright ()); 
  width = desired; 
  } if (Heightmode = = measurespec.exactly) {height = heightsize; 
    else {mpaint.settextsize (mtitletextsize); 
    Mpaint.gettextbounds (mtitle, 0, Mtitle.length (), mbounds); 
    float textHeight = Mbounds.height (); int desired = (int) (Getpaddingtop () + TextHeight + getpaddingbottom ());
    height = desired; 
} setmeasureddimension (width, height); 
 }

Now we modify the layout file:

<relativelayout xmlns:android= "http://schemas.android.com/apk/res/android" 
  xmlns:tools= "http:// Schemas.android.com/tools " 
  xmlns:custom=" http://schemas.android.com/apk/res/com.example.customview01 
  " Android:layout_width= "Match_parent" 
  android:layout_height= "match_parent" > 
 
  < Com.example.customview01.view.CustomTitleView 
    android:layout_width= "wrap_content" 
    android:layout_ height= "Wrap_content" 
    custom:titletext= "3712" 
    android:padding= "10DP" 
    custom:titletextcolor= "# ff0000 " 
    android:layout_centerinparent=" true " 
    custom:titletextsize=" 40sp "/> 
 
</ Relativelayout> 

Now the effect is:

Fully compound our expectations, now we can be the height, width of casual settings, basically can meet our needs.
Of course, this custom view doesn't have a lot of advantages over TextView, and all we feel is adding an event to the custom view:
To add in construction:

This.setonclicklistener (New Onclicklistener () 
    { 
 
      @Override public 
      void OnClick (View v) 
      { 
        Mtitletext = Randomtext (); 
        Postinvalidate (); 
      } 
 
    ); 

 
Private String Randomtext () 
  { 
    Random Random = new Random (); 
    set<integer> set = new Hashset<integer> (); 
    while (Set.size () < 4) 
    { 
      int randomint = Random.nextint (a); 
      Set.add (Randomint); 
    } 
    StringBuffer sb = new StringBuffer (); 
    for (Integer I:set) 
    { 
      sb.append ("" + i); 
    } 
 
    return sb.tostring (); 
  } 

To run the following:

We added a click event, each time it randomly generated a 4-bit random number, interested in the OnDraw can add a bit of noise, and then rewritten as a verification code, is not a good feeling.

Advanced

Here's an example of the basics of a custom view, and here's a slightly more complicated example.
Custom View displays a picture with a text description of the picture, something like a photo introduction, but it's not important to learn how to use custom view.
Direct cut to the chase:
1. In Res/values/attr.xml

<?xml version= "1.0" encoding= "Utf-8"?> 
<resources> 
 
  <attr name= "TitleText" format= "string"/ > 
  <attr name= "titletextsize" format= "Dimension"/> <attr name= " 
  titletextcolor" format= "Color" > 
  <attr name= "image" format= "reference"/> <attr name= 
  "Imagescaletype" > 
    <enum name= " Fillxy "value=" 0 "/> 
    <enum name=" center "value=" 1 "/> 
  </attr> 
 
  <declare-styleable Name = "Customimageview" > 
    <attr name= "TitleText"/> <attr name= 
    "titletextsize"/> 
    Name= the "Titletextcolor"/> 
    <attr name= "image"/> <attr name= 
    "Imagescaletype" 
  /> Declare-styleable> 
 
</resources> 

2. Get our custom attributes in construction:

/** * Initialize the unique custom type * * @param context * @param attrs * @param defstyle * * Customimagevie 
 
    W (context, AttributeSet attrs, int defstyle) {Super (context, attrs, Defstyle); 
 
    TypedArray a = Context.gettheme (). Obtainstyledattributes (Attrs, R.styleable.customimageview, Defstyle, 0); 
 
    int n = a.getindexcount (); 
 
      for (int i = 0; i < n; i++) {int attr = A.getindex (i); Switch (attr) {Case r.styleable.customimageview_image:mimage = Bitmapfactory.decoderesource (getre 
        Sources (), A.getresourceid (attr, 0)); 
      Break 
        Case R.styleable.customimageview_imagescaletype:mimagescale = a.getint (attr, 0); 
      Break 
        Case r.styleable.customimageview_titletext:mtitle = a.getstring (attr); 
      Break 
        Case R.styleable.customimageview_titletextcolor:mtextcolor = A.getcolor (attr, Color.Black); 
      Break Case R.styleable.custOmimageview_titletextsize:mtextsize = A.getdimensionpixelsize (attr, (int) typedvalue.applydimension (TypedValue.C 
        OMPLEX_UNIT_SP, Getresources (). Getdisplaymetrics ())); 
 
      Break 
    } a.recycle (); 
    rect = new Rect (); 
    Mpaint = new Paint (); 
    Mtextbound = new Rect (); 
    Mpaint.settextsize (mtextsize); 
 
  Computed the range mpaint.gettextbounds (mtitle, 0, Mtitle.length (), mtextbound) that depict the font needs; 
 }

3, overriding onmeasure

@Override protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {//Super.onmeasure (Widthmeasurespe 
 
  c, Heightmeasurespec); 
  /** * Set Width */int specmode = Measurespec.getmode (Widthmeasurespec); 
 
  int specsize = measurespec.getsize (Widthmeasurespec); 
    if (Specmode = = measurespec.exactly)//match_parent, Accurate {log.e ("xxx", "exactly"); 
  Mwidth = specsize; 
    else {///the wide int desirebyimg = Getpaddingleft () + getpaddingright () + mimage.getwidth (); 
 
    wide int desirebytitle = Getpaddingleft () + getpaddingright () + mtextbound.width (), as determined by the font; 
      if (Specmode = = measurespec.at_most)//wrap_content {int desire = Math.max (desirebyimg, desirebytitle); 
      Mwidth = Math.min (Desire, specsize); 
    LOG.E ("xxx", "at_most"); 
  }/*** * Set Height * * Specmode = Measurespec.getmode (Heightmeasurespec); 
  Specsize = Measurespec.getsize (Heightmeasurespec); if (Specmode = = Measurespec.exactly)//match_parent, accurate {mheight = specsize; 
    else {int desire = Getpaddingtop () + getpaddingbottom () + mimage.getheight () + mtextbound.height (); 
    if (Specmode = = measurespec.at_most)//wrap_content {mheight = Math.min (Desire, specsize); 
 
} setmeasureddimension (Mwidth, mheight); 
 }

4, overriding OnDraw

@Override protected void OnDraw (Canvas Canvas) {//Super.ondraw (Canvas); 
    /** * Border * * * mpaint.setstrokewidth (4); 
    Mpaint.setstyle (Paint.Style.STROKE); 
    Mpaint.setcolor (Color.cyan); 
 
    Canvas.drawrect (0, 0, getmeasuredwidth (), Getmeasuredheight (), mpaint); 
    Rect.left = Getpaddingleft (); 
    Rect.right = Mwidth-getpaddingright (); 
    Rect.top = Getpaddingtop (); 
 
    Rect.bottom = Mheight-getpaddingbottom (); 
    Mpaint.setcolor (Mtextcolor); 
    Mpaint.setstyle (Style.fill);  /** * The width of the current setting is less than the width required by the font, change the font to XXX ... */if (Mtextbound.width () > Mwidth) {textpaint paint = 
      New Textpaint (Mpaint); String msg = textutils.ellipsize (mtitle, Paint, (float) mwidth-getpaddingleft ()-Getpaddingright (), Textutil 
      s.truncateat.end). toString (); 
 
    Canvas.drawtext (MSG, Getpaddingleft (), Mheight-getpaddingbottom (), mpaint); } else {//Normally, center the font canvas.drawtext (Mtitle, MWIDTH/2-Mtextbound.width () * 1.0F/2, Mheight-getpaddingbottom (), mpaint); 
 
    //Cancel the use of fast rect.bottom-= Mtextbound.height (); 
    if (Mimagescale = = Image_scale_fitxy) {canvas.drawbitmap (mimage, NULL, rect, mpaint); 
      The Rect.left = MWIDTH/2-Mimage.getwidth ()/2; 
      Rect.right = Mwidth/2 + mimage.getwidth ()/2; 
      Rect.top = (Mheight-mtextbound.height ())/2-mimage.getheight ()/2; 
 
      Rect.bottom = (Mheight-mtextbound.height ())/2 + mimage.getheight ()/2; 
    Canvas.drawbitmap (mimage, NULL, rect, mpaint); 
 } 
 
  }

Code, combined with annotations and the use of the Base section view, should be able to read and not understand the message. Here we introduce our custom view:

<linearlayout xmlns:android= "http://schemas.android.com/apk/res/android" xmlns:tools= "http:// Schemas.android.com/tools "xmlns:zhy=" http://schemas.android.com/apk/res/com.zhy.customview02 "Android:layout_ Width= "Match_parent" android:layout_height= "match_parent" android:orientation= "vertical" > <com.zhy.custo Mview02.view.CustomImageView android:layout_width= "wrap_content" android:layout_height= "Wrap_content" Andro Id:layout_margin= "10DP" android:padding= "10DP" zhy:image= "@drawable/ic_launcher" zhy:imagescaletype= "center "zhy:titletext=" Hello Andorid!  
    "Zhy:titletextcolor=" #ff0000 "zhy:titletextsize=" "30sp"/> <com.zhy.customview02.view.customimageview Android:layout_width= "100DP" android:layout_height= "wrap_content" android:layout_margin= "10DP" Androi d:padding= "10DP" zhy:image= "@drawable/ic_launcher" zhy:imagescaletype= "center" zhy:titletext= "Helloworldwel Come "Zhy: titletextcolor= "#00ff00" zhy:titletextsize= "20sp"/> <com.zhy.customview02.view.customimageview Andr Oid:layout_width= "Wrap_content" android:layout_height= "wrap_content" android:layout_margin= "10DP" android:p adding= "10DP" zhy:image= "@drawable/lmj" zhy:imagescaletype= "center" zhy:titletext= "Sister ~" ZHY:TITLETEXTC 
 Olor= "#ff0000" zhy:titletextsize= "12sp"/> </LinearLayout>

I purposely let the display appear in 3 cases:
1, the font width is larger than the picture, and the view width is set to Wrap_content
2, the view width is set to the exact value, the length of the font is greater than this width
3, the picture width is larger than the font, and the view width is set to Wrap_content
Look at the display effect:

How, for these three kinds of situation shows the effect is not bad.

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.