自定义view

自定view分三种:

1、对已有的控件进行拓展

2、对创建复合控件

3、对重写view实现全新view

 

(一)对已有的控件进行拓展

1、我们通常回会重写onDraw方法,对已有的控件进行功能拓展,一般是在onDraw方法中完成功能拓展

@Override
protected void onDraw(Canvas canvas) {
   //完成功能拓展
    super.onDraw(canvas);//完成原生控件的绘制

//或者后面完成功能拓展

}

 

例子:

@SuppressLint("AppCompatCustomView")
public class MyTextView extends TextView {
    private int mViewWidth = 0;
    private Paint mPaint;
    private LinearGradient mLinearGradient;
    private Matrix mGradientMatrix;
    private int mTranslate;

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

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

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        if (mViewWidth == 0) {
            mViewWidth = getMeasuredWidth();
            if (mViewWidth > 0) {
                mPaint = getPaint();
                mLinearGradient = new LinearGradient(0, 0, mViewWidth, 0, new int[]{Color.BLUE, 0xffffffff, Color.BLUE}, 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 > 2 * mViewWidth) {
                mTranslate = -mViewWidth;
            }

            mGradientMatrix.setTranslate(mTranslate, 0);
            mLinearGradient.setLocalMatrix(mGradientMatrix);
            postInvalidateDelayed(100);
        }
    }
}

 

(二)复合控件的自定义view

复合控件一般是由几个view组合为一个新的控件,这个控件一般继承viewgroup

步骤:

1、在res资源文件下面新建attr.xml的属性文件,通过该文件进行代码自定义属性

例如:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="TopBar">
        <!-- 标题内容 -->
        <attr name="title_text" format="string"/>
        <!-- 标题字体大小 -->
        <attr name="title_text_size" format="dimension"/>
        <!-- 标题颜色 -->
        <attr name="title_text_color" format="color"/>
        <!-- 左边按钮的文字 -->
        <attr name="left_text" format="string"/>
        <!-- 左边按钮文字颜色 -->
        <attr name="left_text_color" format="color"/>
        <!-- 左边按钮的背景 -->
        <attr name="left_bg" format="reference|color"/>
        <!-- 右边按钮文字 -->
        <attr name="right_text" format="string"/>
        <!-- 右边按钮文字颜色 -->
        <attr name="right_text_color" format="color"/>
        <!-- 右边按钮背景 -->
        <attr name="right_bg" format="reference|color"/>
    </declare-styleable>
</resources>

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"
    android:layout_width="match_parent"
    android:orientation="horizontal"
    android:layout_height="60dp">

    <Button
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_margin="5dp"
        android:layout_weight="1"
        android:text="button1"
        android:id="@+id/b1"
        android:background="#f4ed79"
        android:textSize="10sp"
        android:gravity="center"/>
    <TextView
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_margin="5dp"
        android:layout_weight="4"
        android:text="text"
        android:id="@+id/t1"
        android:textSize="10sp"
        android:background="#79f4e0"
        android:gravity="center"/>
    <Button
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="button2"
        android:id="@+id/b2"
        android:background="#f4ed79"
        android:layout_margin="5dp"
        android:textSize="10sp"
        android:gravity="center"/>
</LinearLayout>

3、开始写复合控件:

一般是先加载xml的界面,再加载attr.xml的属性,再将属性设置到每个view控件上面

//加载界面并绑定每个view
LayoutInflater.from(context).inflate(R.layout.my_view,this);
 b1=findViewById(R.id.b1);
 b2=findViewById(R.id.b2);
 t1=findViewById(R.id.t1);

//获取属性
TypedArray ta=context.obtainStyledAttributes(attrs,R.styleable.my_view);
b1_text=ta.getString(R.styleable.my_view_b1_text);
b1_text_size=ta.getDimension(R.styleable.my_view_b1_text_size,0);
b1_text_backgroud=ta.getResourceId(R.styleable.my_view_b1_text_backgroud,R.drawable.ic_launcher_foreground);


b2_text=ta.getString(R.styleable.my_view_b2_text);
 b2_text_size=ta.getDimension(R.styleable.my_view_b2_text_size,0);
 b2_text_backgroud=ta.getResourceId(R.styleable.my_view_b2_text_backgroud,R.drawable.ic_launcher_foreground);

 t1_text=ta.getString(R.styleable.my_view_t1_text);
 t1_text_size=ta.getDimension(R.styleable.my_view_t1_text_size,0);
 t1_text_backgroud=ta.getResourceId(R.styleable.my_view_t1_text_backgroud,R.drawable.ic_launcher_foreground);

//设置属性 
 t1.setText(t1_text);
 t1.setTextSize(t1_text_size);
 t1.setBackgroundResource(t1_text_backgroud);

 b1.setText(b1_text);
 b1.setTextSize(b1_text_size);
 b1.setBackgroundResource(b1_text_backgroud);

 b2.setText(b2_text);
 b2.setTextSize(b2_text_size);
 b2.setBackgroundResource(b2_text_backgroud);

4、设置接口

先新建接口,再将接口暴露给用户

interface Listenr{
    public void clickleft();
    public void clickright();
}
Listenr listenr;

public void setListenr(Listenr listenr) {
    this.listenr = listenr;
}

例子:实现自定义控件:

1、界面的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"
    android:layout_width="match_parent"
    android:orientation="horizontal"
    android:layout_height="60dp">

    <Button
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_margin="5dp"
        android:layout_weight="1"
        android:text="button1"
        android:id="@+id/b1"
        android:background="#f4ed79"
        android:textSize="10sp"
        android:gravity="center"/>
    <TextView
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_margin="5dp"
        android:layout_weight="4"
        android:text="text"
        android:id="@+id/t1"
        android:textSize="10sp"
        android:background="#79f4e0"
        android:gravity="center"/>
    <Button
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="button2"
        android:id="@+id/b2"
        android:background="#f4ed79"
        android:layout_margin="5dp"
        android:textSize="10sp"
        android:gravity="center"/>
</LinearLayout>

2、属性attr.xml文件

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="my_view">
        <attr name="b1_text" format="string"/>
        <attr name="b1_text_size" format="dimension"/>
        <attr name="b1_text_backgroud" format="reference|color"/>

        <attr name="b2_text" format="string"/>
        <attr name="b2_text_size" format="dimension"/>
        <attr name="b2_text_backgroud" format="reference|color"/>

        <attr name="t1_text" format="string"/>
        <attr name="t1_text_size" format="dimension"/>
        <attr name="t1_text_backgroud" format="reference|color"/>

    </declare-styleable>

</resources>

3、创建复合控件,进行界面属性的绑定,并设置接口

package com.example.asus.socketapplication.my_view;

import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.example.asus.socketapplication.R;

/**
 * Created by asus on 2018/11/16.
 */

public class MyView extends LinearLayout {
    private Button b1;
    private Button b2;
    private TextView t1;

    private String b1_text;
    private float b1_text_size;
    private int b1_text_backgroud;

    private String b2_text;
    private float b2_text_size;
    private int b2_text_backgroud;

    private String t1_text;
    private float t1_text_size;
    private int t1_text_backgroud;

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


    public void init(Context context,AttributeSet attrs){
        LayoutInflater.from(context).inflate(R.layout.my_view,this);
        b1=findViewById(R.id.b1);
        b2=findViewById(R.id.b2);
        t1=findViewById(R.id.t1);

       TypedArray ta=context.obtainStyledAttributes(attrs,R.styleable.my_view);
       b1_text=ta.getString(R.styleable.my_view_b1_text);
       b1_text_size=ta.getDimension(R.styleable.my_view_b1_text_size,0);
       b1_text_backgroud=ta.getResourceId(R.styleable.my_view_b1_text_backgroud,R.drawable.ic_launcher_foreground);

        b2_text=ta.getString(R.styleable.my_view_b2_text);
        b2_text_size=ta.getDimension(R.styleable.my_view_b2_text_size,0);
        b2_text_backgroud=ta.getResourceId(R.styleable.my_view_b2_text_backgroud,R.drawable.ic_launcher_foreground);

        t1_text=ta.getString(R.styleable.my_view_t1_text);
        t1_text_size=ta.getDimension(R.styleable.my_view_t1_text_size,0);
        t1_text_backgroud=ta.getResourceId(R.styleable.my_view_t1_text_backgroud,R.drawable.ic_launcher_foreground);


        t1.setText(t1_text);
        t1.setTextSize(t1_text_size);
        t1.setBackgroundResource(t1_text_backgroud);

        b1.setText(b1_text);
        b1.setTextSize(b1_text_size);
        b1.setBackgroundResource(b1_text_backgroud);

        b2.setText(b2_text);
        b2.setTextSize(b2_text_size);
        b2.setBackgroundResource(b2_text_backgroud);

        b1.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                listenr.clickleft();
            }
        });

        b2.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                listenr.clickright();
            }
        });

    }

    public String getB1_text() {
        return b1_text;
    }

    public void setB1_text(String b1_text) {
        this.b1_text = b1_text;
        this.invalidate();
    }

    public float getB1_text_size() {
        return b1_text_size;
    }

    public void setB1_text_size(float b1_text_size) {
        this.b1_text_size = b1_text_size;
        this.invalidate();
    }

    public int getB1_text_backgroud() {
        return b1_text_backgroud;
    }

    public void setB1_text_backgroud(int b1_text_backgroud) {
        this.b1_text_backgroud = b1_text_backgroud;
        this.invalidate();
    }

    public String getB2_text() {
        return b2_text;
    }

    public void setB2_text(String b2_text) {
        this.b2_text = b2_text;
        this.invalidate();
    }

    public float getB2_text_size() {
        return b2_text_size;
    }

    public void setB2_text_size(float b2_text_size) {
        this.b2_text_size = b2_text_size;
        this.invalidate();
    }

    public int getB2_text_backgroud() {
        return b2_text_backgroud;
    }

    public void setB2_text_backgroud(int b2_text_backgroud) {
        this.b2_text_backgroud = b2_text_backgroud;
        this.invalidate();
    }

    public String getT1_text() {
        return t1_text;
    }

    public void setT1_text(String t1_text) {
        this.t1_text = t1_text;
        this.invalidate();
    }

    public float getT1_text_size() {
        return t1_text_size;
    }

    public void setT1_text_size(float t1_text_size) {
        this.t1_text_size = t1_text_size;
        this.invalidate();
    }

    public int getT1_text_backgroud() {
        return t1_text_backgroud;
    }

    public void setT1_text_backgroud(int t1_text_backgroud) {
        this.t1_text_backgroud = t1_text_backgroud;
        this.invalidate();
    }

    interface Listenr{
        public void clickleft();
        public void clickright();
    }
    Listenr listenr;

    public void setListenr(Listenr listenr) {
        this.listenr = listenr;
    }
}

4、再其他地方使用复合控件

<com.example.asus.socketapplication.my_view.MyView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:b1_text="left"
    app:b1_text_size="10dp"
    app:b1_text_backgroud="#f7ee57"
    app:b2_text="right"
    app:b2_text_size="10dp"
    app:b2_text_backgroud="#f7ee57"
    app:t1_text="center"
    app:t1_text_size="10dp"
    app:t1_text_backgroud="#57eaf7"/>

 

(三)实现全新自定义控件

1、全新view

1.1view有三种测试模式:

1.2、EXACTLY精确模式,view的长宽都是精确的数字,或者充满父布局

1.3、TO-MOST最大模式,该模式下view的长宽都不能超过父布局的长宽就可以

1.4、UNSPECIFIED未指定,view可以任意大下

2、如果view的长宽是自适应,就需要重写

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

}

 

3、如果自定义viewgroup:

重写

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

}

重写:

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {

}

 

(四)事件传递,及事件拦截

(1)public boolean dispatchTouchEvent(MotionEvent ev)这个方法用来分发TouchEvent

(2)public boolean onInterceptTouchEvent(MotionEvent ev)这个方法用来拦截TouchEvent

(3)public boolean onTouchEvent(MotionEvent ev)这个方法用来处理TouchEvent

事件传递viewgroup->view->viewgroup

viewgoup拦截外部解决:

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            //  保存当前touch的纵坐标值
            touch = (int) ev.getRawY();
            break;
        case MotionEvent.ACTION_MOVE:
            //  滑动距离大于slop值时,返回true,父容器拦截
            if (Math.abs((int) ev.getRawY() - touch) > slop|| mGestureDetector.onTouchEvent(ev))
                return true;
            break;
    }

    return super.onInterceptTouchEvent(ev) ;
}

子view消费内部解决:

 /**
32      * 使用 outter.requestDisallowInterceptTouchEvent();
33      * 来决定父控件是否对事件进行拦截
34      * @param ev
35      * @return
36      */
37     @Override
38     public boolean dispatchTouchEvent(MotionEvent ev) {
39         int x = (int) ev.getX();
40         int y = (int) ev.getY();
41         switch (ev.getAction()) {
42             case MotionEvent.ACTION_DOWN:
43                 mHorizontalEx2.requestDisallowInterceptTouchEvent(true);
44                 break;
45             case MotionEvent.ACTION_MOVE:
46                 final int deltaX = x-lastYIntercepted;
47                 final int deltaY = y-lastYIntercepted;
48                 if(Math.abs(deltaX)>Math.abs(deltaY)){
49                     mHorizontalEx2.requestDisallowInterceptTouchEvent(false);
50                 }
51                 break;
52             case MotionEvent.ACTION_UP:
53                 break;
54         }
55         lastXIntercepted = x;
56         lastYIntercepted = y;
57         return super.dispatchTouchEvent(ev);
58     }
59 }

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值