Android 自定义View--入门篇

概述

自定义View是Android程序员在进阶阶段是必须经历的也是痛苦的,但是它也没有想象的那么麻烦,无非也就是一下几步:

1. 自定义View属性
2. 在构造方法中获得自定义的属性
3. 重新ononDraw:用来绘制该控件的内容
4. 重新onMeasure:用来确定该控件或子控件的大小
5. 重新onLayout:用来确定该控件及子控件在父窗体中的位置

并不是说每次都要重写这些方法,这个还要看实际情况。

实现目标

<img src="http://upload-images.jianshu.io/upload_images/2260249-8c39124081a528a0.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240"/>

实现方式

1. 自定义View属性:res/values下新建attrs.xml,在里面声明需要的属性

<?xml version="1.0" encoding="utf-8"?>
<resources> 
   <declare-styleable name="FloatCricleView">    
         <attr name="viewText" format="string"></attr>     
         <attr name="viewTextSize" format="dimension"></attr>    
         <attr name="viewBackground" format="color"></attr>  
         <attr name="viewTextColor" format="color"></attr>   
 </declare-styleable>
</resources>

2. 那么我们如何实现这些属性呢?

在View的构造方法中获得属性,首先我们有必要介绍一下这几个构造方法

public int width;//布局宽
public int height;//布局的高
private Paint circlePaint;//圆画笔
private Paint textPaint;//文字画笔
private int textSize;
private int colorBackground;
private int textColor;
private String text;
public FloatCricleView(Context context) {
    this(context, null);
}
public FloatCricleView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
}
public FloatCricleView(Context context, AttributeSet attrs, int defStyleAttr) { 
    super(context, attrs, defStyleAttr);   
    TypedArray array = context.obtainStyledAttributes(attrs,    R.styleable.FloatCricleView, defStyleAttr, 0);  
    int size = array.getIndexCount(); 
    //设置一些默认参数  
    colorBackground = Color.GRAY;//背景色   
    textColor = Color.BLACK;//文字颜色  
    textSize = 20;//文字大小   
    text = "NULL";   
    for (int i = 0; i < size; i++) {    
      int attr = array.getIndex(i);    
      switch (attr) {         
      case R.styleable.FloatCricleView_viewText:     
           text = array.getString(attr); 
           break;        
      case R.styleable.FloatCricleView_viewTextColor:       
         textColor = array.getColor(attr, Color.BLACK);         
         break;         
      case R.styleable.FloatCricleView_viewTextSize:            
        textSize = array.getDimensionPixelSize(attr, 20);         
        break;        
      case R.styleable.FloatCricleView_viewBackground:        
        colorBackground = array.getColor(attr, Color.GRAY);   
        break;     
       default:          
       break;    
    }    
}  
  initView();//初始化画笔
}
private void initView() { 
    circlePaint = new Paint();
    circlePaint.setColor(colorBackground); 
    circlePaint.setAntiAlias(true);  
    textPaint = new Paint(); 
    textPaint.setTextSize(textSize); 
    textPaint.setAntiAlias(true);  
    textPaint.setFakeBoldText(true); 
    textPaint.setColor(textColor);
}

我们重写了3个构造方法,默认的布局文件调用的是两个参数的构造方法,所以记得让所有的构造调用我们的三个参数的构造,我们在三个参数的构造中获得自定义属性。

3. 重新onDraw,onMeasure

QQ截图20161024160136.jpg
@Overrideprotected void onDraw(Canvas canvas) { 
   super.onDraw(canvas);  
    canvas.drawCircle(width / 2, height / 2, width / 2, circlePaint);
    float textWidth = textPaint.measureText(text);
    float x = width / 2 - textWidth / 2;
    Paint.FontMetrics metrics = textPaint.getFontMetrics();
    float dy = -(metrics.ascent + metrics.descent) / 2; 
    float y = height / 2 + dy;
    canvas.drawText(text, x, y, textPaint);
}
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  //设置宽度
    int specMode = View.MeasureSpec.getMode(widthMeasureSpec); 
    int specSize = View.MeasureSpec.getSize(widthMeasureSpec);
    switch (specMode) {     
      case View.MeasureSpec.EXACTLY://明确指定大小的,或者最大  
          width = getPaddingLeft() + getPaddingRight() + specSize;
          break; 
       case View.MeasureSpec.AT_MOST://一般为warp_content
            width = getPaddingLeft() + getPaddingRight() + dip2px(getContext(), 100);
            break;
    }  
  //设置高度  
   specMode = View.MeasureSpec.getMode(heightMeasureSpec); 
   specSize = View.MeasureSpec.getSize(heightMeasureSpec); 
   switch (specMode) {   
       case View.MeasureSpec.EXACTLY:     
            height = getPaddingTop() + getPaddingBottom() + specSize;  
            break;    
       case View.MeasureSpec.AT_MOST:  
            height = getPaddingTop() + getPaddingBottom() + dip2px(getContext(), 100);        
            break;  
  }  
  setMeasuredDimension(width, height);}

4. 工具方法

/**
 * dp 转 px
 * 
 * @param context 
 * @param value 
 * @return 
 */
private static int dip2px(Context context, float value) { 
    final float scale = context.getResources().getDisplayMetrics().density;
    return (int) (value * scale + 0.5f);
}
/**
 * px转dp 
 *
 * @param context
 * @param value
 * @return 
 */
private static int px2dip(Context context, float value) {  
    final float scale = context.getResources().getDisplayMetrics().density;
    return (int) (value / scale + 0.5f);
}

5. 使用

<tangren.szxb.com.floatcrileview.FloatCricleView2         
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"    
    android:layout_centerHorizontal="true"
    android:layout_centerVertical="true"     
    add:viewBackground="@color/colorAccent"   
    add:viewText="90%"  
    add:viewTextColor="@color/colorPrimary"  
    add:viewTextSize="20sp" />

6. 结束语

实现的效果也比较简单大神勿喷,至此我的第一篇简书文章也写完了,希望大家相互学习沟通交流,我的csdn地址:http://blog.csdn.net/wu996489865 。因为我是第一次在简书上发布自己的文章,我想问的是为什么代码不会自动换行,我都是手动回车换行的啊(泪崩)!还请大神们指点一二(抱拳)!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容