1.继承View组件,比如,LabelView继承了View
 
2.重写两个构造方法,比如,对于自定义View LabelView
 
LabelView(Context context),如果该自定义View是通过代码来实例化的,那么,就需要该构造方法;
LabelView(Context context, AttributeSet attrs),通过布局文件XML来使用该自定义View,那么,就需要该构造方法。
 
    /**
     * Constructor.  This version is only needed if you will be instantiating
     * the object manually (not from a layout XML file).
     * @param context
     */
    public LabelView(Context context) {
        super(context);
        initLabelView();
    }
 /**
     * Construct object, initializing with any attributes we understand from a
     * layout file. These attributes are defined in
     * SDK/assets/res/any/classes.xml.
     *
     * @see android.view.View#View(android.content.Context, android.util.AttributeSet)
     */
    public LabelView(Context context, AttributeSet attrs) {
        super(context, attrs);
   ....
     }
 
3.重写onDraw(Canvas canvas)和onMeasure(int measureWidth, int measureHeight)
 
onDraw(Canvas canvas),在实现自定义View的时候,你自己要创建一个Paint对象,用来设置自定义View的外观,尺寸,颜色。
然后,再在onDraw方法中,将图形绘制在系统传递过来的画布对象Canvas。
也就是说,系统回调onDraw来实现自定义View的渲染。
 
onMeasure(int measureWidth, int measureHeight),系统回调该方法,告诉你现在自定义View的宽度和高度是怎样设置的。
通过MeasureSpec.getMode(measureWidth),MeasureSpec.getSize(measureWidth)可以得到当前宽度的模式和大小。通过模式,可以知道用户设置的是wrap,match_parent,还是设置一个具体值,还说没有任何限制;通过大小,可以知道,当前系统检测到的当前View组件的宽度。
 
在得到这些信息后,你可以自己自定义,设置你想要的View组件的宽度和高度。
 
 
上面三个,就是自定义View的关键步骤。
 
-----------------------------------------------------------
 
其它方面:
1.Paint对象和Canvas的使用
 
要绘制一个自定义View,首先,你自己要确定出,图形的最终样式。按照最终样式,使用Paint对象,绘制出最终样式。Canvas对象的使用也需要关注。所以,在绘制图形的时候,要知道怎么使用Paint对象和Canvas绘制出最终的图形。
 
这方面的知识,需要补充。
 
 
2.属性设置
用户在使用你实现的自定义View的时候,它想自己定义View的属性,它想通过View提供的属性控制View的外观,尺寸,颜色等特征。那么,你实现的自定义View,就要提供给用户设置属性,并且要接收到用户传递过来的属性值,根据这些属性值构造出Paint对象。
这个的实现步骤:
1).在res目录下的values目录,创建一个attrs.xml,然后,在里面添加属性描述。如下:声明了三个属性。
 
2).然后,在自定义View的类中,声明setter方法,如下:
根据用户传递过来的属性,重新绘制自定义VIew。requestLayout()的调用,会触发系统回调onMeasure(int measureWidth, int measureHeight)方法;invalidate()的调用,会触发系统回调onDraw()方法。
/**
        * Sets the text to display in this label
        *
        * @param text
        *            The text to display. This will be drawn as one line.
        */
        public void setText(String text) {
               mText = text;
               requestLayout();
              invalidate();
       }
 
 
3).在使用该自定义View的布局文件中,要声明该自定义View的命名空间,如下:
声明了一个命名空间
xmlns:app = "http://schemas.android.com/apk/res/com.example.customview"
红色部分,是该自定义View所在的包。
然后,你就可以使用app:text,这样命名空间加属性名的方式来设置属性。属性名,与attrs.xml中声明名字一样。
< RelativeLayout xmlns:android ="http://schemas.android.com/apk/res/android"
    xmlns:tools= "http://schemas.android.com/tools"
    xmlns:app= "http://schemas.android.com/apk/res/com.example.customview"
    android:layout_width= "match_parent"
    android:layout_height= "match_parent" >
 
    <com.example.customview.LabelView
        android:id ="@+id/oneLabelView"
        android:layout_width ="wrap_content"
        android:layout_height ="wrap_content"
        app:text= "Somethine"
        app:textColor ="#00868B"
        app:textSize ="34sp" />
 
</ RelativeLayout>
 
---------------下面是实现例子--------------------------
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View; /**
* Example of how to write a custom subclass of View. LabelView is used to draw
* simple text views. Note that it does not handle styled text or right-to-left
* writing systems.
*
*/
public class LabelView extends View {
private Paint mTextPaint;
private String mText;
private int mAscent; /**
* Constructor. This version is only needed if you will be instantiating the
* object manually (not from a layout XML file).
*
* @param context
*/
public LabelView(Context context) {
super(context);
initLabelView();
} /**
* Construct object, initializing with any attributes we understand from a
* layout file. These attributes are defined in
* SDK/assets/res/any/classes.xml.
*
* @see android.view.View#View(android.content.Context,
* android.util.AttributeSet)
*/
public LabelView(Context context, AttributeSet attrs) {
super(context, attrs);
initLabelView(); TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.LabelView); CharSequence s = a.getString(R.styleable.LabelView_text);
if (s != null) {
setText(s.toString());
} // Retrieve the color(s) to be used for this view and apply them.
// Note, if you only care about supporting a single color, that you
// can instead call a.getColor() and pass that to setTextColor().
setTextColor(a.getColor(R.styleable.LabelView_textColor, 0xFF000000)); int textSize = a.getDimensionPixelOffset(
R.styleable.LabelView_textSize, 0);
if (textSize > 0) {
setTextSize(textSize);
} a.recycle();
} private final void initLabelView() {
mTextPaint = new Paint();
mTextPaint.setAntiAlias(true);
// Must manually scale the desired text size to match screen density
mTextPaint.setTextSize(16 * getResources().getDisplayMetrics().density);
mTextPaint.setColor(0xFF000000);
setPadding(3, 3, 3, 3);
} /**
* Sets the text to display in this label
*
* @param text
* The text to display. This will be drawn as one line.
*/
public void setText(String text) {
mText = text;
requestLayout();
invalidate();
} /**
* Sets the text size for this label
*
* @param size
* Font size
*/
public void setTextSize(int size) {
// This text size has been pre-scaled by the getDimensionPixelOffset
// method
mTextPaint.setTextSize(size);
requestLayout();
invalidate();
} /**
* Sets the text color for this label.
*
* @param color
* ARGB value for the text
*/
public void setTextColor(int color) {
mTextPaint.setColor(color);
invalidate();
} /**
* @see android.view.View#measure(int, int)
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(measureWidth(widthMeasureSpec),
measureHeight(heightMeasureSpec));
} /**
* Determines the width of this view
*
* @param measureSpec
* A measureSpec packed into an int
* @return The width of the view, honoring constraints from measureSpec
*/
private int measureWidth(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec); if (specMode == MeasureSpec.EXACTLY) {
// We were told how big to be
result = specSize;
} else {
// Measure the text
result = (int) mTextPaint.measureText(mText) + getPaddingLeft()
+ getPaddingRight();
if (specMode == MeasureSpec.AT_MOST) {
// Respect AT_MOST value if that was what is called for by
// measureSpec
result = Math.min(result, specSize);
}
} return result;
} /**
* Determines the height of this view
*
* @param measureSpec
* A measureSpec packed into an int
* @return The height of the view, honoring constraints from measureSpec
*/
private int measureHeight(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec); mAscent = (int) mTextPaint.ascent();
if (specMode == MeasureSpec.EXACTLY) {
// We were told how big to be
result = specSize;
} else {
// Measure the text (beware: ascent is a negative number)
result = (int) (-mAscent + mTextPaint.descent()) + getPaddingTop()
+ getPaddingBottom();
if (specMode == MeasureSpec.AT_MOST) {
// Respect AT_MOST value if that was what is called for by
// measureSpec
result = Math.min(result, specSize);
}
}
return result;
} /**
* Render the text
*
* @see android.view.View#onDraw(android.graphics.Canvas)
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawText(mText, getPaddingLeft(), getPaddingTop() - mAscent,
mTextPaint);
}
}

自定义View的实现流程的更多相关文章

  1. 自定义View分类与流程

    自定义View分类与流程(进阶篇)## 转载出处: http://www.gcssloop.com/customview/CustomViewProcess/ 自定义View绘制流程函数调用链(简化版 ...

  2. Android查缺补漏(View篇)--自定义 View 的基本流程

    View是Android很重要的一部分,常用的View有Button.TextView.EditView.ListView.GridView.各种layout等等,开发者通过对这些View的各种组合以 ...

  3. 自定义View的基本流程

    1.明确需求,确定你想实现的效果2.确定是使用组合控件的形式还是全新自定义的形式,组合控件即使用多个系统控件来合成一个新控件,你比如titilebar,这种形式相对简单,参考:http://blog. ...

  4. 从一个简洁的进度刻度绘制中了解自定义View的思路流程

    先看效果(原谅我的渣像素),进度的刻度.宽度.颜色可以随意设定: [项目github地址: https://github.com/zhangke3016/CircleLoading] 实现起来并不难, ...

  5. 自定义View(1)简单流程及示例模板

    1,继承View , ViewGroup,或TextView等等 2,绘制相关的api, canvas 画布, paint 画笔 2,重写重要的函数(注意这个顺序) onMeasure 属于View的 ...

  6. 自定义控件(视图)2期笔记01:自定义控件之自定义View的步骤

    1. 根据Android Developers官网的介绍,自定义控件你需要以下的步骤: (1)创建View (2)处理View的布局 (3)绘制View (4)与用户进行交互 (5)优化已定义的Vie ...

  7. Android -- 自定义view实现keep欢迎页倒计时效果

    1,最近打开keep的app的时候,发现它的欢迎页面的倒计时效果还不错,所以打算自己来写写,然后就有了这篇文章. 2,还是老规矩,先看一下我们今天实现的效果 相较于我们常见的倒计时,这次实现的效果是多 ...

  8. Android查缺补漏(View篇)--自定义View利器Canvas和Paint详解

    上篇文章介绍了自定义View的创建流程,从宏观上给出了一个自定义View的创建步骤,本篇是上一篇文章的延续,介绍了自定义View中两个必不可少的工具Canvas和Paint,从细节上更进一步的讲解自定 ...

  9. 自定义View实战--实现一个清新美观的加载按钮

    本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 在 Dribble 上偶然看到了一组交互如下: 当时在心里问自己能不能做,答案肯定是能做的,不过我比较懒,觉得中间那个伸缩变化要编写 ...

随机推荐

  1. 第一章 Java Web应用开发技术

    Java Web应用开发是基于JavaEE(JavaEnterprise Edition)框架的,而JavaEE是建立在Java平台上的企业级应用解决方案.JavaEES框架提供的Web开发技术主要支 ...

  2. python切片详解

    先从原理上分析切片运算: list的切片,内部是调用__getitem__,__setitem__,__delitem__和slice函数.而slice函数又是和range()函数相关的. 给切片传递 ...

  3. CSS基础小记

    2017/10/29 CSS 认识CSS样式 CSS全称为"层叠样式表 (Cascading Style Sheets)",它主要是用于定义HTML内容在浏览器内的显示样式,如文字 ...

  4. Linux的ll命令详解

    ll 列出来的结果详细,有时间,是否可读写等信息 ,象windows里的 详细信息 ls 只列出文件名或目录名 就象windows里的 列表 ll -t 是降序,  ll -t | tac 是升序 l ...

  5. LintCode-165.合并两个排序链表

    合并两个排序链表 将两个排序链表合并为一个新的排序链表 样例 给出 1->3->8->11->15->null,2->null, 返回 1->2->3- ...

  6. 检测固定IP的端口是否开放批出

    因为运维工作经常需要telnet某个IP的端口是否正常,因此有了下文 .BAT内容如下: @echo off for /f %%i in ('type ip.txt') do ( echo %%i t ...

  7. JAVA IDE IntelliJ IDEA使用简介(三)—之你不能忘记的快捷键

    IDEA有许多的快捷键来帮助你更便捷的编写代码,以下列出的快捷键(默认情况下,你还没有定制你的快捷键)是工作中经常需要使用到的,请牢记 快捷键 描述 备注 Alt+F1 视图切换 切换当前工作文件的视 ...

  8. JDK各个版本比较 JDK5~JDK9

    JDK5 自动装箱与拆箱: 枚举 静态导入,如:import staticjava.lang.System.out 可变参数(Varargs) 内省(Introspector),主要用于操作JavaB ...

  9. 【hdu4734】F(x) 数位dp

    题目描述 对于一个非负整数 $x=​​\overline{a_na_{n-1}...a_2a_1}$ ,设 $F(x)=a_n·2^{n-1}+a_{n-1}·2^{n-2}+...+a_2·2^1+ ...

  10. 【bzoj2073】[POI2004]PRZ 状态压缩dp

    题目描述 一只队伍在爬山时碰到了雪崩,他们在逃跑时遇到了一座桥,他们要尽快的过桥. 桥已经很旧了, 所以它不能承受太重的东西. 任何时候队伍在桥上的人都不能超过一定的限制. 所以这只队伍过桥时只能分批 ...