安卓自定义view(全面)

Posted 春招进大厂的梦想家

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了安卓自定义view(全面)相关的知识,希望对你有一定的参考价值。

安卓自定义view

一、view的测量

1.测量的模式:

  • EXACTLY :精确值模式,当把空间的layout_width属性或者layout_height的属性设置为具体的数值时,或者指定为match_parent时候,系统就是使用的EXACTLY 模式;
  • AT_MOST: 最大值模式,当空间的layout_width属性或者layout_height属性指定为wrap_content时候,控件大小跟着控件的内容变化而变化,此时控件的尺寸只要不超过父控件允许的最大尺寸即可。
  • UNSPECIFIED: 这个属性比较奇怪,不指定其测量大小模式,view想多大就多大,通常情况下只有在绘制自定义view的时候才会使用

2.简单演示如何进行view的测量

1.自定义一个类继承自View
public class one extends View {
    public one(Context context) {
        super(context);
    }

    public one(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public one(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    //重写onMeasure方法来进行测量
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(measureWidth(widthMeasureSpec),
       measureHeight(heightMeasureSpec));
    }

    //测量高度
    private int measureHeight(int heightMeasureSpec) {
        //第一步,从MeasureSpec对象中提取出具体的测量模式和大小
        int specMode = MeasureSpec.getMode(heightMeasureSpec);
        int specSize = MeasureSpec.getSize(heightMeasureSpec);

        int result = 0;

        //检测是否是精确值模式
        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        }else{
            //如果不是就自己设定
            result = 200;
            if (specMode== MeasureSpec.AT_MOST) {
                result = Math.min(result,specSize);
            }
        }
        return result;
    }

    private int measureWidth(int widthMeasureSpec) {
        int specMode = MeasureSpec.getMode(widthMeasureSpec);
        int specSize = MeasureSpec.getSize(widthMeasureSpec);

        int result = 0;

        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        }else{
            result = 200;
            if (specMode== MeasureSpec.AT_MOST) {
                result = Math.min(result,specSize);
            }
        }
        return result;
    }

}

2.新建一个xml文件来作为自定义view的载体
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <View
        android:layout_width="400px"
        android:layout_height="400px"
        android:background="#00ff0f"/>

</LinearLayout>
3.在main活动的xml文件下添加自定义的控件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <com.example.customize_learning.learning.one
        android:layout_width="400px"
        android:layout_height="400px"/>

</LinearLayout>

主要是进行测量,测量的主要步骤就是重写onMeasure方法,在代码中有很详细的注释

二、view的绘制

简单来说就是继承view之后再重写onDraw方法,并在Canvas对象上来绘制需要的图形

以绘制一个闪光的文字作为例子

1.新建一个类及其xml文件

public class MyTextView extends TextView {

    private int mViewWidth;
    private Paint mPaint;
    private LinearGradient mLinearGradient;
    private Matrix mGradientMatrix;

    private int mTranslate;

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

    public MyTextView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mPaint = new Paint();
        if (mViewWidth == 0){
            mViewWidth = getMeasuredWidth();
            if (mViewWidth>0) {
                mPaint = getPaint();
                /**
                 * LinearGradient构造方法中的参数int[] color:
                 * 第一个元素:发光字体闪过后所显示的字体颜色,这里给定与第三个元素一样
                 * 第二个元素:字体发光的颜色
                 * 第三个元素:原字体显示的颜色
                 *
                 * mViewWidth:设置发光的宽度
                 * */
                mLinearGradient = new LinearGradient(0,
                        0,
                        mViewWidth,
                        0,
                        new int[]{0x22ffffff, 0xffffffff, 0x22ffffff},
                        null,
                        Shader.TileMode.CLAMP);
                mPaint.setShader(mLinearGradient);
                //创建矩形
                mGradientMatrix = new Matrix();
            }
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mGradientMatrix != null) {
            mTranslate += mViewWidth / 5;
            if (mTranslate > mViewWidth * 2) {
                mTranslate = -mViewWidth;
            }
            mGradientMatrix.setTranslate(mTranslate, 0);
            mLinearGradient.setLocalMatrix(mGradientMatrix);
            //控制闪过的时间
            postInvalidateDelayed(80);
        }
    }

}

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="我是一个会闪烁的TextView"/>

</FrameLayout>

2.将自定义控件添加到主活动的xml文件下面

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">
    <com.example.customize_learning.learning.MyTextView
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:layout_marginTop="30dp"/>
</LinearLayout>

三、组合自定义控件

1.先建一个类,因为是组合控件,使其继承自RelativeLayout

2建一个xml文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_marginLeft="35dp">
        <Button
            android:id="@+id/plus_btn"
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:textSize="18sp"
            android:background="@drawable/selector_left"
            android:text="+">
        </Button>

        <EditText
            android:id="@+id/values_edt"
            android:gravity="center"
            android:layout_gravity="center"
            android:layout_width="100dp"
            android:layout_height="wrap_content"
            android:text="0"/>

        <Button
            android:id="@+id/minus_btn"
            android:background="@drawable/selector_right"
            android:layout_width="100dp"
            android:text="-"
            android:textSize="18sp"
            android:layout_height="wrap_content">
        </Button>
    </LinearLayout>

</LinearLayout>

在这里插入图片描述

3.设置按钮按下和松开时候不同的效果

(1)设置左右两边按钮的自定义背景(按下时)

左边

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <!--纯色填充-->
    <solid android:color="#DFE8DF"/>

    <!--设置圆角-->
    <corners android:bottomLeftRadius="10dp"
        android:topLeftRadius="10dp"/>

    <!--渐变色-->
    <gradient android:startColor="#EC1426"
        android:angle="270"
        android:centerColor="#C64B7C"
        android:endColor="#71363D"
        android:type="linear"/>
</shape>

右边

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <solid android:color="#DFE8DF"/>

    <corners android:bottomRightRadius="10dp"
        android:topRightRadius="10dp"/>

    <!--渐变色-->
    <gradient android:startColor="#EC1426"
        android:angle="270"
        android:centerColor="#C64B7C"
        android:endColor="#71363D"
        android:type="linear"/>


</shape>
(2)设置不触碰时左右两边按钮的自定义背景

左边

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <!--纯色填充-->
    <solid android:color="#DFE8DF"/>

    <!--设置圆角-->
    <corners android:bottomLeftRadius="10dp"
        android:topLeftRadius="10dp"/>

    <!--渐变色-->
    <gradient android:startColor="#14EC14"
        android:angle="270"
        android:centerColor="#4BC64B"
        android:endColor="#367143"
        android:type="linear"/>

</shape>>

右边

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <solid android:color="#DFE8DF"/>

    <corners android:bottomRightRadius="10dp"
        android:topRightRadius="10dp"/>

    <!--渐变色-->
    <gradient android:startColor="#14EC14"
        android:angle="270"
        android:centerColor="#4BC64B"
        android:endColor="#367143"
        android:type="linear"/>

</shape>
(3)设置一个选择器,实现按下和松开展示不同的背景

左边

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">


    <item android:state_pressed="true" android:drawable="@drawable/shape_number_btn_bg_left_presses"/>

    <item android:drawable="@drawable/shape_number_btn_bg_left"/>

</selector>

右边

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">


    <item android:state_pressed="true" android:drawable="@drawable/shape_number_btn_bg_right_pressed"/>

    <item android:drawable="@drawable/shape_number_btn_bg_right"/>

</selector>

4.把自定义控件添加到主活动里边去

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical"安卓自定义view仿小米商城购物车动画

Android自定义View实战教程5??---Canvas详解及代码绘制安卓机器人

Android自定义View实战教程5??---Canvas详解及代码绘制安卓机器人

安卓自定义View文章数据滚动显示数值

Path类的最全面详解 - 自定义View应用系列

安卓自定义view小实例 + MVC 思想