android 自定义控件

一般写自定义控件是为了增加控件的属性或者做一些复杂的控件避免每次都写一些麻烦的布局,自定义view也不一定很复杂,可以很简单的实现。

1、view其实可以分自绘控件、组合控件、以及继承控件这三种

2、先简单介绍一下view绘制的三个方法

1、measure操作
     measure操作主要用于计算视图的大小,即视图的宽度和长度。在view中定义为final类型,要求子类不能修改。measure()函数中又会调用下面的函数:
     (1)onMeasure(),视图大小的将在这里最终确定,也就是说measure只是对onMeasure的一个包装,子类可以覆写onMeasure()方法实现自己的计算视图大小的方式,并通过setMeasuredDimension(width, height)保存计算结果。
 
2、layout操作
     layout操作用于设置视图在屏幕中显示的位置。在view中定义为final类型,要求子类不能修改。layout()函数中有两个基本操作:
     (1)setFrame(l,t,r,b),l,t,r,b即子视图在父视图中的具体位置,该函数用于将这些参数保存起来;
     (2)onLayout(),在View中这个函数什么都不会做,提供该函数主要是为viewGroup类型布局子视图用的;
 
3、draw操作
     draw操作利用前两部得到的参数,将视图显示在屏幕上,到这里也就完成了整个的视图绘制工作。子类也不应该修改该方法,因为其内部定义了绘图的基本操作:
     (1)绘制背景;
     (2)如果要视图显示渐变框,这里会做一些准备工作;
     (3)绘制视图本身,即调用onDraw()函数。在view中onDraw()是个空函数,也就是说具体的视图都要覆写该函数来实现自己的显示(比如TextView在这里实现了绘制文字的过程)。而对于ViewGroup则不需要实现该函数,因为作为容器是“没有内容“的,其包含了多个子view,而子View已经实现了自己的绘制方法,因此只需要告诉子view绘制自己就可以了,也就是下面的dispatchDraw()方法;
     (4)绘制子视图,即dispatchDraw()函数。在view中这是个空函数,具体的视图不需要实现该方法,它是专门为容器类准备的,也就是容器类必须实现该方法;
     (5)如果需要(应用程序调用了setVerticalFadingEdge或者setHorizontalFadingEdge),开始绘制渐变框;
     (6)绘制滚动条;

3、这里实现自绘控件,主要用到onMeasure()和onDraw()方法,实现过程是先实现onMeasure()和onDraw()方法,在onMeasure中获取到控件宽高

然后通过onDraw进行绘制,实现比较简单,这里是点击一次屏幕加一。

package com.example.apple.autobutton.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * Created by apple on 17/3/18.
 */

public class CounterView extends View {

    private Paint mPaint;
    private int height;
    private int width;
    private int Count = 1;
    private Rect mBounds;

    public CounterView(Context context) {
        this(context, null);
    }

    public CounterView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

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

        mPaint = new Paint();
        mBounds = new Rect();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        height = heightMeasureSpec;//获取控件宽高
        width = widthMeasureSpec;
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        mPaint.setColor(Color.BLACK);
        canvas.drawRect(0, 0, width, height, mPaint);
        mPaint.setColor(Color.RED);
        mPaint.setTextSize(30);
        String text = String.valueOf(Count);
        mPaint.getTextBounds(text, 0, text.length(), mBounds);
        float textWidth = mBounds.width();
        float textHeight = mBounds.height();
        canvas.drawText(text, getWidth() / 2 - textWidth / 2, getHeight() / 2 + textHeight / 2, mPaint);

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        Count++;
        invalidate();//重绘视图
        return super.onTouchEvent(event);

    }

}
4、第二种是 组合控件的使用,主要是将几个不同的控件组合起来使用,这里只是使用了button和textView实现简单的购物按钮

代码布局是

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerVertical="true"
    android:background="@drawable/btn_add_sub_view_selector"
    android:orientation="horizontal">

    <Button
        android:id="@+id/btn_sub"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:background="@drawable/btn_number_view_selector"
        android:gravity="center"
        android:text=""
        android:textSize="20sp" />

    <TextView
        android:id="@+id/tv_value"
        android:layout_width="40dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:gravity="center"
        android:text="1" />

    <Button
        android:id="@+id/btn_add"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:background="@drawable/btn_number_view_selector"
        android:gravity="center"
        android:text=""
        android:textSize="20sp" />

</LinearLayout>
自定义view中代码实现:其实也比较简单,先加载布局文件,初始化三个控件然后添加监听事件,还加了一个接口回调,可以回调到activity进行处理

package com.example.apple.autobutton.view;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.support.v7.widget.TintTypedArray;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.example.apple.autobutton.R;


/**
 * Created by apple on 17/3/17.
 */

public class NumberAddSubView extends LinearLayout implements View.OnClickListener {

    private Button btn_sub;
    private TextView tv_value;
    private Button btn_add;

    private int value = 1;
    private int minValue = 1;
    private int maxValue = 10;

    private OnNumberClickLister listener;

    public int getValue() {

        String valueStr = tv_value.getText().toString().trim();
        if (!TextUtils.isEmpty(valueStr)) {

            value = Integer.valueOf(valueStr);
        }
        return value;
    }

    public void setValue(int value) {
        this.value = value;

        tv_value.setText(value + "");
    }

    public int getMinValue() {
        return minValue;
    }

    public void setMinValue(int minValue) {
        this.minValue = minValue;
    }

    public int getMaxValue() {
        return maxValue;
    }

    public void setMaxValue(int maxValue) {
        this.maxValue = maxValue;
    }

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
    public NumberAddSubView(Context context) {
        this(context, null);
    }


    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
    public NumberAddSubView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
    public NumberAddSubView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        View.inflate(context, R.layout.number_view, this);
        btn_sub = (Button) findViewById(R.id.btn_sub);
        tv_value = (TextView) findViewById(R.id.tv_value);
        btn_add = (Button) findViewById(R.id.btn_add);

        getValue();

        //设置点击事件
        btn_sub.setOnClickListener(this);
        btn_add.setOnClickListener(this);

        if (attrs != null) {
            TintTypedArray typedArray = TintTypedArray.obtainStyledAttributes(context, attrs, R.styleable.NumberAddSubView);

            //设置值
            int value = typedArray.getInt(R.styleable.NumberAddSubView_value, 0);
            if (value > 0){
                setValue(value);
            }

            //设置最小值
            int minValue = typedArray.getInt(R.styleable.NumberAddSubView_minValue, 0);
            if (value > 0){
                setMinValue(minValue);
            }

            //设置最大值
            int maxValue = typedArray.getInt(R.styleable.NumberAddSubView_maxValue, 0);
            if (value > 0){
                setMaxValue(maxValue);
            }
            //设置背景
            Drawable numberAddSubBackground = typedArray.getDrawable(R.styleable.NumberAddSubView_NumberAddSubBackground);
            if (numberAddSubBackground!=null){
                setBackground(numberAddSubBackground);
            }
            //加号背景
            Drawable numberAddBackground = typedArray.getDrawable(R.styleable.NumberAddSubView_NumberAddBackground);
            if (numberAddBackground!=null){
                btn_add.setBackground(numberAddBackground);
            }
            //减号背景
            Drawable numberSubBackground = typedArray.getDrawable(R.styleable.NumberAddSubView_NumberSubBackground);
            if (numberSubBackground!=null){
                btn_sub.setBackground(numberSubBackground);
            }

        }
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {

            case R.id.btn_sub://减
                subNumber();
                if (listener != null) {
                    listener.onButtonSub(v, value);
                }

                break;

            case R.id.btn_add://加
                addNumber();
                if (listener != null) {
                    listener.onButtonAdd(v, value);
                }
                break;
        }
    }

    private void addNumber() {
        if (value < maxValue) {
            value++;
        }
        setValue(value);
    }

    private void subNumber() {
        if (value > minValue) {
            value--;
        }
        setValue(value);
    }

    /**
     * 监听数字增加减少控件
     */
    public interface OnNumberClickLister {
        /**
         * 当减少按钮被点击的时候回调
         *
         * @param view
         * @param value
         */
        void onButtonSub(View view, int value);

        /**
         * 当增加按钮被点击的时候回调
         *
         * @param view
         * @param value
         */
        void onButtonAdd(View view, int value);
    }


    /**
     * 监听数字按钮
     *
     * @param listener
     */
    public void setOnNumberClickLister(OnNumberClickLister listener) {
        this.listener = listener;
    }

}
5、 继承控件的使用,如名字所说,就是继承一个控件,然后可以在控件里面增加方法,下面简单实现,就修改控件大小。

package com.example.apple.autobutton.view;

import android.content.Context;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.widget.ImageView;

/**
 * Created by apple on 17/3/18.
 *
 *继承自定义view
 */

public class AccedeView extends ImageView {

    public AccedeView(Context context) {
        this(context, null);
    }

    public AccedeView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

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


    /**
     * 设置视频宽高
     * @param imageViewWidth
     * @param imageViewHeight
     */
    public void setImageViewSize(int imageViewWidth,int imageViewHeight){
        ViewGroup.LayoutParams params = getLayoutParams();

        params.width = imageViewWidth;
        params.height = imageViewHeight;

        setLayoutParams(params);
        //requestLayout();
    }
}

6、自定义控件引用布局代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:atguigu="http://schemas.android.com/apk/res-auto"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.apple.autobutton.MainActivity">

    <com.example.apple.autobutton.view.NumberAddSubView
        android:id="@+id/number_add_sub_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        atguigu:NumberAddSubBackground="@drawable/btn_add_sub_view_selector"
        atguigu:NumberSubBackground="@drawable/btn_sub_selector"
        atguigu:NumberAddBackground="@drawable/btn_add_selector"
        atguigu:maxValue="20"
        atguigu:minValue="1"
        atguigu:value="1">

    </com.example.apple.autobutton.view.NumberAddSubView>

    <com.example.apple.autobutton.view.CounterView
        android:id="@+id/counter_view"
        android:layout_width="100dp"
        android:layout_height="100dp" />

    <com.example.apple.autobutton.view.AccedeView
        android:id="@+id/accede"
        android:background="@drawable/add"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>
7、activity代码

package com.example.apple.autobutton;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

import com.example.apple.autobutton.view.AccedeView;
import com.example.apple.autobutton.view.CounterView;
import com.example.apple.autobutton.view.NumberAddSubView;

public class MainActivity extends AppCompatActivity {

    private NumberAddSubView number_add_sub_view;
    private CounterView counter_view;
    private AccedeView accede;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();
    }

    private void initView() {

        counter_view = (CounterView)findViewById(R.id.counter_view);
        accede = (AccedeView)findViewById(R.id.accede);
        accede.setImageViewSize(200,200);

        number_add_sub_view = (NumberAddSubView)findViewById(R.id.number_add_sub_view);
        number_add_sub_view.setOnNumberClickLister(new NumberAddSubView.OnNumberClickLister() {
            @Override
            public void onButtonSub(View view, int value) {

            }

            @Override
            public void onButtonAdd(View view, int value) {

            }
        });


    }
}
最后实现效果图


测试代码下载地址http://download.csdn.net/detail/u011324501/9785727

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值