自定义view初探(一)

初次自定义view,绘制了一个表,点击表针会转动。自定义的控件的尽量将可以从外部设置的属性暴露出来,这样增加控件适用场合和灵活性。

思路

  • extends view并实现其中的onDraw方法来实现绘制图形
  • 重写其中的ClockView(Context context, AttributeSet attrs)来实现在xml中的引用
  • implements View.OnClickListener来实现监听点击
  • 重写onSizeChanged方法实现部分参数的初始化和对界面尺寸变化的适应

参数说明

    private int count_clicked=0;//点击次数
    private float mborderwidth;//画笔宽度
    private int mbordercolor;//线条颜色

    private Paint mPaint;//画笔
    private RectF mBounds;//矩形
    private float mWidth;//矩形区宽度
    private float mHeight;//矩形区高度
    private float mRadius;//指针半径
    private float smalllength;//小刻度长
    private float largerlength;//大刻度长
1.创建一个ClockView继承自view并实现View.OnClickListener方法,一定要记得重载其中的第二个构造器,这样才能在xml中引用
public class ClockView extends View implements View.OnClickListener 

 public ClockView(Context context) 
 public ClockView(Context context, AttributeSet attrs)
 public ClockView(Context context, AttributeSet attrs, int defStyleAttr) 
2.为了在xml中设置属性,为控件设置属性,在values下创建attrs.xml文件
<resources>
    <declare-styleable name="ClockView">
        <attr name="border_color" format="color"/>
        <attr name="border_width" format="dimension"/>
    </declare-styleable>
</resources>
3.重写构造方法,从xml中解析属性,初始化一些数据
public ClockView(Context context, AttributeSet attrs) {
        super(context, attrs);

        //获取xml中的自定义属性
        TypedArray typedArray=context.getTheme().obtainStyledAttributes(
                attrs,R.styleable.ClockView,0,0);  
                mbordercolor=typedArray.getColor(R.styleable.ClockView_border_color,0xff000000); 
                   mborderwidth=typedArray.getDimension(R.styleable.ClockView_border_width, 2);

    InitPara();
    setOnClickListener(this);
    }
4.初始化画笔并处理点击事件,每次点击旋转6度,一共可以旋转60次,count_clicked记录需要旋转的次数(在每个构造器中添加InitPara(); setOnClickListener(this);)
private void InitPara(){
        mPaint=new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(mborderwidth);
        mPaint.setColor(mbordercolor);
    }
 @Override
 public void onClick(View v) {
        count_clicked++;//控制表针的转动位置
        if(count_clicked%60==0){
            count_clicked=0;
        }
        invalidate();//重新绘制,调用onDraw
    }    
5.重写onSizeChanged,并进行一些数据初始化
/**
     * 当界面的尺寸发生改变时调用
     * @param w
     * @param h
     * @param oldw
     * @param oldh
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        mBounds=new RectF(getLeft(),getTop(),getRight(),getBottom());
        mWidth=mBounds.right-mBounds.left;
        mHeight=mBounds.bottom-mBounds.top;
        if(mHeight<mWidth){
            mRadius=mHeight/4;
        }else{
            mRadius=mWidth/4;
        }

        smalllength=30;
        largerlength=60;
    }
6.自定义ClockDraw(canvas, count_clicked)用来绘制自定义的图形
private void ClockDraw(Canvas canvas,int count){
        //绘制底色和矩形框
        canvas.drawColor(0xff000000);
        canvas.drawRoundRect(new RectF(mBounds.centerX()-(float)0.9*mWidth/2,
                mBounds.centerY() - (float)0.9*mHeight/2,
                mBounds.centerX() + (float)0.9*mWidth/2,
                mBounds.centerY() + (float)0.9*mHeight/2), 30, 30, mPaint);
        mPaint.setColor(mbordercolor);
        //绘制表盘的刻度
        float start_x,start_y;
        float end_x,end_y;
        for(int i=0;i<60;i++)
        {
            start_x=mRadius*(float)Math.cos(Math.PI / 180 * i * 6);
            start_y=mRadius*(float)Math.sin(Math.PI/180*i*6);
            if(i%5==0){
                end_x=(mRadius+largerlength)*(float)Math.cos(Math.PI / 180 * i * 6);
                end_y=(mRadius+largerlength)*(float)Math.sin(Math.PI/180*i*6);
            }else {
                end_x=(mRadius+smalllength)*(float)Math.cos(Math.PI / 180 * i * 6);
                end_y=(mRadius+smalllength)*(float)Math.sin(Math.PI/180*i*6);
            }
            start_x+=mBounds.centerX();
            start_y+=mBounds.centerY();
            end_x+=mBounds.centerX();
            end_y+=mBounds.centerY();
            canvas.drawLine(start_x,start_y,end_x,end_y,mPaint);
        }
        canvas.drawCircle(mBounds.centerX(), mBounds.centerY(), mRadius, mPaint);//表盘的圆
        canvas.drawCircle(mBounds.centerX(), mBounds.centerY(), 20, mPaint);//表芯的圆
        canvas.rotate(6 * count, mBounds.centerX(), mBounds.centerY());//旋转画布,坐标系跟随画布旋转
        canvas.drawLine(mBounds.centerX(), mBounds.centerY(), mBounds.centerX(), mBounds.centerY() - mRadius, mPaint);
    }

7.重写onDraw方法,调用自己的Draw方法

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        ClockDraw(canvas, count_clicked);
    }
在xml中调用自定义的view,设置颜色和线条粗细
<com.demo.eric.defineview.ClockView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:border_color="#eaf1e90b"
        app:border_width="4dp"/>

完成!!!

未点击
点击后

总结:

重点是onDraw中的重写,在onDraw中进行一系列的图形绘制;canvas作为画布,利用paint在canvas上调用canvas.drawXXX(X,X,X,……,paint)绘制自己想要的图形。

ClockView整体源码

/**
 * Created by Administrator on 2016/1/7 0007.
 */
public class ClockView extends View implements View.OnClickListener {

    private int count_clicked=0;//点击次数
    private float mborderwidth;//画笔宽度
    private int mbordercolor;//线条颜色

    private Paint mPaint;//画笔
    private RectF mBounds;//矩形
    private float mWidth;//矩形区宽度
    private float mHeight;//矩形区高度
    private float mRadius;//指针半径
    private float smalllength;//小刻度长
    private float largerlength;//大刻度长


    public ClockView(Context context) {
        super(context);
        setOnClickListener(this);
        InitPara();
    }

    public ClockView(Context context, AttributeSet attrs) {
        super(context, attrs);

        //获取xml中的自定义属性
        TypedArray typedArray=context.getTheme().obtainStyledAttributes(
                attrs,R.styleable.ClockView,0,0);

        mbordercolor=typedArray.getColor(R.styleable.ClockView_border_color,0xff000000);
        mborderwidth=typedArray.getDimension(R.styleable.ClockView_border_width, 2);
        InitPara();
        setOnClickListener(this);
    }

    public ClockView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        InitPara();
        setOnClickListener(this);
    }

    private void InitPara(){
        mPaint=new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(mborderwidth);
        mPaint.setColor(mbordercolor);
    }

    /**
     * 当界面的尺寸发生改变时调用
     * @param w
     * @param h
     * @param oldw
     * @param oldh
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        mBounds=new RectF(getLeft(),getTop(),getRight(),getBottom());
        mWidth=mBounds.right-mBounds.left;
        mHeight=mBounds.bottom-mBounds.top;
        if(mHeight<mWidth){
            mRadius=mHeight/4;
        }else{
            mRadius=mWidth/4;
        }

        smalllength=30;
        largerlength=60;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        ClockDraw(canvas, count_clicked);
    }

    private void ClockDraw(Canvas canvas,int count){
        //绘制底色和矩形框
        canvas.drawColor(0xff000000);
        canvas.drawRoundRect(new RectF(mBounds.centerX()-(float)0.9*mWidth/2,
                mBounds.centerY() - (float)0.9*mHeight/2,
                mBounds.centerX() + (float)0.9*mWidth/2,
                mBounds.centerY() + (float)0.9*mHeight/2), 30, 30, mPaint);
        mPaint.setColor(mbordercolor);
        //绘制表盘的刻度
        float start_x,start_y;
        float end_x,end_y;
        for(int i=0;i<60;i++)
        {
            start_x=mRadius*(float)Math.cos(Math.PI / 180 * i * 6);
            start_y=mRadius*(float)Math.sin(Math.PI/180*i*6);
            if(i%5==0){
                end_x=(mRadius+largerlength)*(float)Math.cos(Math.PI / 180 * i * 6);
                end_y=(mRadius+largerlength)*(float)Math.sin(Math.PI/180*i*6);
            }else {
                end_x=(mRadius+smalllength)*(float)Math.cos(Math.PI / 180 * i * 6);
                end_y=(mRadius+smalllength)*(float)Math.sin(Math.PI/180*i*6);
            }
            start_x+=mBounds.centerX();
            start_y+=mBounds.centerY();
            end_x+=mBounds.centerX();
            end_y+=mBounds.centerY();
            canvas.drawLine(start_x,start_y,end_x,end_y,mPaint);
        }
        canvas.drawCircle(mBounds.centerX(), mBounds.centerY(), mRadius, mPaint);//表盘的圆
        canvas.drawCircle(mBounds.centerX(), mBounds.centerY(), 20, mPaint);//表芯的圆
        canvas.rotate(6 * count, mBounds.centerX(), mBounds.centerY());//旋转画布,坐标系跟随画布旋转
        canvas.drawLine(mBounds.centerX(), mBounds.centerY(), mBounds.centerX(), mBounds.centerY() - mRadius, mPaint);

    }

    @Override
    public void onClick(View v) {
        count_clicked++;
        if(count_clicked%60==0){
            count_clicked=0;
        }
        invalidate();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值