自定义view快速入门(2)--实例与知识点相结合

  上一篇中,了解了基本概念和初次体验了自定义view,接下来以一个实例来梳理一下知识点。

  需求:自定义一个View,在设置一个数字之后,有一个自增的效果。

  效果如图:
  这里写图片描述
  
  如你所见,这是上一篇自定义view实例的改进,不过没读上一篇也不影响这次阅读。

一,声明新的属性:

<attr name="myTitle" format="string"/>

声明的属性,即 format有一下类型:

  1. string
    字符串
  2. color
    颜色
  3. dimension
    尺寸值
  4. integer
    整型
  5. enum
    枚举
  6. reference
    资源ID
  7. float
    浮点型
  8. fraction
    百分数
  9. flag
    位或运算

二,添加相关的逻辑:

  
初始化参数,

    public AddTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setColor(getResources().getColor(R.color.colorAccent));
        mPaint.setAlpha(4);
        num = 0;
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyString);
        mTitle = ta.getString(R.styleable.MyString_myTitle);
        setText(mTitle);
    }

初始化画笔Paint,Paint是作用在Canvas上的,就像我们显示生活中画画一样,需要纸和笔。在Android中,Canvas相当于纸,而Paint相当于笔。在这里,初始化了Paint(笔)的颜色,透明度,填充模式,和抗锯齿的属性。
然后,通过Typedarray 获取到xml中的属性值。并通过setText(),来将文本显示出来。
 
   测量view:
   

        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthResult = 0;

        if (widthSpecMode == MeasureSpec.EXACTLY) {
            widthResult = widthSpecSize;
        } else {
            widthResult = 200;
            if (widthSpecMode == MeasureSpec.AT_MOST) {
                widthResult = Math.min(widthResult, widthSpecSize);
            }
        }

一般情况下,如果没有用到wrap_content,是不用重写onMeasure()方法的。因为wrap_content,匹配的是AT_MOST模式(尽可能多),系统是不知道要分配多少的,所以得重写onMeasure()给出一个默认的指,即,使用wrap_content时,就会使用默认的指。上面的这段代码就是进行响应的判断,并给出默认的指。

 
 三,绘制背景
 

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawRect(0,0,getRight(),getBottom(),mPaint);
        invalidate();
    }

在上一篇的例子中,我使用了xml直接设置背景,在这里,我用Canvas和Paint来绘制背景。如上,在绘制矩形之后,调用了invalidate()进行刷新UI。

四,响应触控操作

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                break;
            case MotionEvent.ACTION_MOVE:
                break;
            case MotionEvent.ACTION_UP:
                translateNum = 0;
                mOnMyClickListener.click();
                break;
        }
        postInvalidate();
        return true;
    }

这里通过接口回调暴露了接口给调用者,如果对接口回调不太熟悉,可以尽情google一把。

    public void setNum(final int num) {
        this.num = num;
        if (num > 1000) {
            addNum = num / 35;
        } else {
            addNum = num / 15;
        }
        add();
    }

    public void add() {
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                translateNum += addNum;
                setText(String.valueOf(translateNum));
                postInvalidate();
                invalidate();
                if (translateNum > num) {
                    setText(String.valueOf(num));
                    postInvalidate();
                    return;
                }
                add();
            }
        }, 50);
    }

通过handler实现延迟和循环调用,当给出的数字大于1000时,将数字分35次进行相加,否则分15次进行相加。最后因为在new Runnable中,所以使用postInvalidate();刷新UI。
  

最后各部分代码是这样的:

声明属性部分:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyString">
        <attr name="myTitle" format="string"/>
    </declare-styleable>
</resources>

自定义AddTextView部分:

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;

/**
 * Created by zone on 2017/1/22.
 */

public class AddTextView extends TextView {

    private String mTitle;
    private int num;
    private int translateNum;
    private int addNum;
    private Handler mHandler = new Handler();
    private OnMyClickListener mOnMyClickListener;
    private Paint mPaint;

    public void setOnMyClickListener(OnMyClickListener onMyClickListener) {
        mOnMyClickListener = onMyClickListener;
    }

    public interface OnMyClickListener {
        void click();
    }

    public AddTextView(Context context) {
        super(context);
    }

    public AddTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setColor(getResources().getColor(R.color.colorAccent));
        mPaint.setAlpha(4);
        num = 0;
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyString);
        mTitle = ta.getString(R.styleable.MyString_myTitle);
        setText(mTitle);
    }

    public AddTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthResult = 0;

        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightResult = 0;

        if (widthSpecMode == MeasureSpec.EXACTLY) {
            widthResult = widthSpecSize;
        } else {
            widthResult = 200;
            if (widthSpecMode == MeasureSpec.AT_MOST) {
                widthResult = Math.min(widthResult, widthSpecSize);
            }
        }
        if (heightSpecMode == MeasureSpec.EXACTLY) {
            heightResult = heightSpecSize;
        } else {
            heightResult = 200;
            if (widthSpecMode == MeasureSpec.AT_MOST) {
                heightResult = Math.min(heightResult, heightSpecSize);
            }
        }
        setMeasuredDimension(widthResult, heightResult);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawRect(0,getBottom()/10,getRight(),getBottom(),mPaint);
        invalidate();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                break;
            case MotionEvent.ACTION_MOVE:
                break;
            case MotionEvent.ACTION_UP:
                translateNum = 0;
                mOnMyClickListener.click();
                break;
        }
        postInvalidate();
        return true;
    }


    public void setNum(final int num) {
        this.num = num;
        if (num > 1000) {
            addNum = num / 35;
        } else {
            addNum = num / 15;
        }
        add();
    }

    public void add() {
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                translateNum += addNum;
                setText(String.valueOf(translateNum));
                postInvalidate();
                invalidate();
                if (translateNum > num) {
                    setText(String.valueOf(num));
                    postInvalidate();
                    return;
                }
                add();
            }
        }, 50);
    }
}

UI引用部分:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.zone.custonview.MainActivity">
    <com.zone.custonview.AddTextView
        android:id="@+id/mytextview"
        android:layout_width="180px"
        android:layout_height="180px"
        android:gravity="center"
        android:textSize="20dp"
        custom:myTitle="111111111111111"/>
</LinearLayout>

Activity部分:

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private AddTextView mAddTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mAddTextView = (AddTextView) findViewById(R.id.mytextview);
        mAddTextView.setOnMyClickListener(new AddTextView.OnMyClickListener() {
            @Override
            public void click() {
                mAddTextView.setNum(4000);
            }
        });
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值