电商_简单了解自定义View

自定义控件

当Android原生的控件无法满足我们的需要时,又或者说我们想实现一个特别炫的控件,又或者说我们就是想展示自己,就想和别人不一样,这时候我们就不得不去自己去一步一步的去创建一个控件,也就是自己定义一个控件。

派系

说到自定义控件的实现,从当下所分的派系而言,可以衍生出三大派:
第一种实现方式就是继承已有的控件来实现自定义控件:主要是当要实现的控件和已有的控件在很多方面比较类似, 通过对已有控件的扩展来满足要求。比如说,我想让一个TextView不仅可以添加文字也可以添加图片,那么我们就可以继承Textview控件。
第二种通过继承一个布局文件实现自定义控件,一般来说做组合控件时可以通过这个方式来实现。注意此时不用onDraw方法,在构造广告中通过inflater加载自定义控件的布局文件,再addView(view),自定义控件的图形界面就加载进来了。
第三种就是通过继承view类来实现自定义控件,使用GDI绘制出组件界面,一般无法通过上述两种方式来实现时用该方式

GDI

什么是GDI?大家不妨可以百度一下,在这里我也粘贴一下GDI是Graphics Device
Interface的缩写,含义是图形设备接口,它的主要任务是负责系统与绘图程序之间的信息交换,处理所有Windows程序的图形输出。

构造方法

第一个构造函数:当不需要使用xml声明或者不需要使用inflate动态加载时候,实现此构造函数即可
第二个构造函数: 当需要在xml中声明此控件,则需要实现此构造函数。并且在构造函数中把自定义的属性与控件的数据成员连接起来。
第三个构造函数:接受一个style资源

属性

步骤

1、创建attrs.xml属性文件
2、TypedArray ty =context.obtainStyledAttributes(attrs, R.styleable.BannerView);
3、xmlns:app=“http://schemas.android.com/apk/res-auto

自定义属性:
reference:参考某一资源ID,以此类推

(1)属性定义:

<declare-styleable name = "名称"><attr name = "background" format = "reference" /></declare-styleable>

(2)属性使用:

<ImageViewandroid:layout_width = "42dip"android:layout_height = "42dip"android:background = "@drawable/图片ID"    />

color:颜色值

<declare-styleable name = "名称"><attr name = "textColor" format = "color" /></declare-styleable>

boolean:布尔值

<declare-styleable name = "名称"><attr name = "focusable" format = "boolean" /></declare-styleable>

dimension:尺寸值。注意,这里如果是dp那就会做像素转换

<declare-styleable name = "名称"><attr name = "layout_width" format = "dimension" /></declare-styleable>

float:浮点值。
integer:整型值。
string:字符串
fraction:百分数。
enum:枚举值
flag:是自己定义的,类似于 android:gravity=“top”,就是里面对应了自己的属性值。
reference|color:颜色的资源文件。
reference|boolean:布尔值的资源文件

主要方法

其实话又说回来Android的UI界面都是由View和ViewGroup及其派生类组合而成的,其中最重要的三个方法是onMeasure(int,int),onLayout(boolean,int,int,int,int),onDraw(Cancas),当然了除了这三种方法之外,还有很多方法,这里我们先主要阐述一下这三个方法是怎么个意思

@Override
// 当系统测量view的大小的时候,调用
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        	super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        	// 我们必须告诉系统,这个view有多大,通过调用
        	setMeasuredDimension(width, height)
        	setMeasuredDimension(200, 80);
  	 	}
	}
	@Override
    /**
     * 当系统指定view的位置后,回调该方法 ,view的位置,由父view决定,子view只有建议权,没有决定权
     * @params changed 当前view的尺寸和位置,是否发生变化
     * @params left,top,right,bottom 当前view在父view中的位置
     */
    protected void onLayout(boolean changed, int left, int top, int right,int bottom) {
        super.onLayout(changed, left, top, right, bottom);
    }
 	@Override
    /*** 绘制view的内容*/
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.GREEN);
    }

onFinishlnflate()这是一个回调方法, 当应用从 XML 布局文件加载该组件并利用它来构建界面之后, 该方法就会被回调。

onMeasure(int,int):调用该方法来检测View组件及它所包含的所有子组件的大小.onlayout(boolean,int,int,int,int):当该组件需要分配其子组件的位置、大小时,该方法就会被回调.View类中布局发生改变时会调用的方法,这个方法是所有View、ViewGroup及其派生类都具有的方法,重载该类可以在布局发生改变时作定制处理,这在实现一些特效时非常有用。

onSizeChanged(int,int, int, int):当该组件的大小被改变时回调该方法.

onDraw(canves): 当该组件将要绘制它的内容时回调该方法迸行绘制.View类中用于重绘的方法,这个方法是所有View、ViewGroup及其派生类都具有的方法,也是AndroidUI绘制最重要的方法。开发者可 重载该方法,并在重载的方法内部基于参数canvas绘制自己的各种图形、图像效果。

onKeyDown(int,KeyEvent): 当某个键被按下时触发该方法.

onKayUp(int,KeyEvent), 当松开某个键时触发该方法.

onTrackballEvent (MotionEvent): 当发生轨迹球事件时触发该方法.

onTouchEvent (MotionEvent): 当发生触摸屏事件时触发该方法.

onWindowFocuschanged(boolean): 当该组件得到、失去焦点时触发该方法.

onAttachedToWindow():当把该组件放入某个窗口时触发该方法.

onDetachedFromWindow(): 当把该组件从某个窗口上分离时触发该方法.

onWindowVisibilityChanged(int):当包含该组件的窗口的可见性发生改变时触发该方法.

另外再补充两个ViewGroup类经常重载的方法:

1.protected void dispatchDraw(Canvas canvas):ViewGroup类及其派生类具有的方法,这个方法主要用于控制子View的绘制分发,重载该方法可改变子View的绘制,进而实现一些复杂的视效。
2.protected boolean drawChild(Canvas canvas, View child, long drawingTime)):ViewGroup
类及其派生类具有的方法,这个方法直接控制绘制某局具体的子view,重载该方法可控制具体某个具体子View

onMeasure

如果当父控件设置为match_parent时,自定义的View采用默认的onMeasure函数,行为如下:
(1)CustomView设置为 match_parent 或者 wrap_content 没有任何区别,其显示大小由父控件决定,它会填充满整个父控件的空间。
2)CustomView设置为固定的值,则其显示大小为该设定的值。如果你的自定义控件的大小计算就是跟系统默认的行为一致的话,那么你就不需要重写onMeasure函数了

private int getMySize(int defaultSize, int measureSpec) {
        int mySize = defaultSize;
        int mode = MeasureSpec.getMode(measureSpec);
        int size = MeasureSpec.getSize(measureSpec);
        switch (mode) {
            case MeasureSpec.UNSPECIFIED: {//如果没有指定大小,就设置为默认大小            
                mySize = defaultSize;
                break;
            }
            case MeasureSpec.AT_MOST: {//如果测量模式是最大取值为size,我们将大小取最大值,你也可以取其他值            
                mySize = size;
                break;
            }
            case MeasureSpec.EXACTLY: {//如果是固定的大小,那就不要去改变它            
                mySize = size;
                break;
            }
        }
        return mySize;
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = getMySize(100, widthMeasureSpec);
        int height = getMySize(100, heightMeasureSpec);
        if (width < height) {
            height = width;} else {
            width = height;
        } setMeasuredDimension(width, height);
    }

猜你喜欢

转载自blog.csdn.net/qq_43797842/article/details/88688962