android studio|Android 自定义 view 控件实例

更新时间:2020-03-23    来源:.Net开发    手机版     字体:

【www.bbyears.com--.Net开发】

Android自定义view通过继承系统的View并重写部分方法来满足自己的特定需要。首先我们来看一下都有哪些方法可能需要被重写:   

    onMeasure() 检测View组件及其子组件的大小
    onLayout() 当该组件需要分配其子组件的位置、大小时
    onTouchEvent 当发生触屏事件时
    onDraw() 当组件将要绘制它的内容时
    onKeyDown 当按下某个键盘时
    onKeyUp  当松开某个键盘时
    onTrackballEvent 当发生轨迹球事件时
    onSizeChange() 当该组件的大小被改变时
    onFinishInflate() 回调方法,当应用从XML加载该组件并用它构建界面之后调用的方法
    onWindowFocusChanged(boolean)  当该组件得到、失去焦点时
    onAtrrachedToWindow() 当把该组件放入到某个窗口时
    onDetachedFromWindow() 当把该组件从某个窗口上分离时触发的方法
    onWindowVisibilityChanged(int): 当包含该组件的窗口的可见性发生改变时触发的方法
 
红色标注的部分是我们经常需要重写的函数。具体的实现我们举一个简单的例子来说明,首先上效果图:

 
圆形和文字跟随触摸事件移动的一个简单的自定义view

实现上面的效果我们大致需要分成这几步
    在res/values/  下建立一个attrs.xml 来声明自定义view的属性
    一个继承View并复写部分函数的自定义view的类
    一个展示自定义view 的容器界面

我们的view 叫做myView,一定要和我们的class文件名相同。它有一个属性值,格式为color




   
       
   

        


2.在自定义view类中实现其构造函数(用于初始获得view的属性配置)和复写onDraw和onTouchEvent。

public class myView extends View{
    //定义画笔和初始位置
    Paint p = new Paint();
    public float currentX = 50;
    public float currentY = 50;
    public int textColor;

    public myView(Context context, AttributeSet attrs) {
        super(context, attrs);
        //获取资源文件里面的属性,由于这里只有一个属性值,不用遍历数组,直接通过R文件拿出color值
        //把属性放在资源文件里,方便设置和复用
        TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.myView);
        textColor = array.getColor(R.styleable.myView_TextColor,Color.BLACK);
        array.recycle();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //画一个蓝色的圆形
        p.setColor(Color.BLUE);
        canvas.drawCircle(currentX,currentY,30,p);
        //设置文字和颜色,这里的颜色是资源文件values里面的值
        p.setColor(textColor);
        canvas.drawText("BY finch",currentX-30,currentY+50,p);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        currentX = event.getX();
        currentY = event.getY();
        invalidate();//重新绘制图形
        return true;

    }
}

这里思路很简单,通过不断的更新当前位置坐标和重新绘制图形实现效果,要注意的是使用TypedArray后一定要记得recycle(),否则会对下次调用产生影响。

除非你不会再用TypedArray. 


3.我们把myView放在activity_main.xml里面,当然也可以在代码中通过addview函数加到布局中。


    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:myview="http://schemas.android.com/apk/res-auto"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="finch.scu.cn.myview.MainActivity">

            android:layout_width="match_parent"
        android:layout_height="match_parent"
        myview:TextColor="#ff0000"
        />


这里 xmlns:自定义控件的前缀="http://schemas.android.com/apk/res/包名(或res-auto)" , 前缀:TextColor="#ff0000"。如果不申明命名空间属性就会


最后是MainActivity

public class MainActivity extends AppCompatActivity {

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

具体的view要根据具体的需求来,比如我们要侧滑删除的listview我们可以继承listview,监听侧滑事件,显示删除按钮实现功能。




Android自定义View的实现

自定义View首先要实现一个继承自View的类。添加类的构造方法,override父类的方法,如onDraw,(onMeasure)等。如果自定义的View有自己的属性,需要在values下建立attrs.xml文件,在其中定义属性,同时代码也要做修改。

一个简单的例子:

・新建一个MyView类,继承自TextView,并添加构造方法:

package com.example.xhelloworld;

import android.content.Context;

import android.widget.TextView;

public class MyView extends TextView{

    public MyView(Context context) {

       super(context);

       // TODO Auto-generated constructor stub

    }

}

・再在主activity中调用。方法是setContentView(new MyView(this));这句

package com.example.xhelloworld;

import android.app.Activity;

import android.os.Bundle;

import android.view.Menu;

public class NewView extends Activity {

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        //setContentView(R.layout.activity_newview);

        setContentView(new MyView(this));

       

    }

    @Override

    public boolean onCreateOptionsMenu(Menu menu) {

        getMenuInflater().inflate(R.menu.activity_newview, menu);

        return true;

    }

}

运行后的结果为:


这样一个简单的自定义View就可以使用了。可以改变一下背景颜色,在MyView类中添加:

@Override

    protected void onDraw(Canvas canvas) {

       // TODO Auto-generated method stub

       super.onDraw(canvas);

       canvas.drawColor(Color.BLUE);

    }

即可完成。运行结果


上面的例子很简单,没有涉及到属性的添加。使用范围很小,不能在布局文件中使用。如果要在布局文件中用到,还需要添加一个构造方法:

public MyView(Context context,AttributeSet attrs){

       super(context, attrs);  

    }

当然,上面只是在code中做的修改,在xml文件(main.xml)中也需要进行如下操作:


        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        />

至少在xml文件中写上上面的内容。其中com.example.xhelloworld.NewView这句是需要显示的控件所代表的类。Com.example.xhelloworld是类的包名,NewView是类名。这个类肯定是继承自View的自定义类(其实就是,使我们自己写的,这是废话了。。。),可以是在工程中直接源码添加xxxx.java的,也可以是在libs目录下自己新添加的jar包里面的。如果是jar包里面的一个类,则路径就是jar包里面,这个类的路径。

完成上面的两步之后就可以在代码中实例化这个布局文件了

@Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        //setContentView(new MyView(this));

显示的效果同上图。

下面介绍如何实现自定义View的属性设置。实现自定义View的属性设置,需要:

・在values目录下建立attrs.xml文件,添加属性内容

・在布局文件中添加新的命名空间xmlns,然后可以使用命名空间给自定义的空间设置属性

・设置完属性之后,当然还要对其进行处理。在自定义View类中的构造方法中进行处理

根据这三步给一个例子进行说明一下

首先添加attrs.xml文件,在定义属性

 



   

   

   

    declare-styleable>

resources>

然后在布局文件中完成:

xmlns:my=http://schemas.android.com/apk/res/com.example.xhelloworld


       android:layout_width="fill_parent"

       android:layout_height="wrap_content"   

       my:textColor="#FFFFFFFF"   

       my:textSize="22dp"

    />

注:这步我在实现的时候出错,问题是显示找不到属性textColor和textSize,这奇怪的错误。解决方法是,在写my:textColor="#FFFFFFFF" 时,写到my之后,按alt+/,这是会自动添加一个xmlns,和my的路径是一样的,用生成的这个替换掉my就可以了。奇葩的问题就用奇葩的方法解决。起初我也不知道怎么弄,瞎搞出来的。

最后在MyView.java中添加另一个构造方法,并添加代码来处理从xml中获得的属性

public MyView(Context context,AttributeSet attrs){

       super(context, attrs);

         mPaint = new Paint();  

        //TypedArray是一个用来存放由context.obtainStyledAttributes获得的属性的数组  

        //在使用完成后,一定要调用recycle方法  

        //属性的名称是styleable中的名称+“_”+属性名称  

        //TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MyView);

        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MyView);

        int textColor = array.getColor(R.styleable.MyView_textColor, 0XFF00FF00); //提供默认值,放置未指定  

        float textSize = array.getDimension(R.styleable.MyView_textSize, 36);  

        mPaint.setColor(textColor);  

        mPaint.setTextSize(textSize);  

        array.recycle(); //一定要调用,否则这次的设定会对下次的使用造成影响  

      

    }

 

完成之后就已经实现了自定视图的构造,自定义视图属性的添加很处理。现在完成的是一般的自定义视图,继承自TextView或者View等视图,也就是通过程序主UI线程完成更新的视图,如果是自定义SurfaceView,实现方法有所不同。

添加完之后肯定有很多疑问,自己去做可能还不能理解。这里再对上面操作进行解释说明。

背后的事

View类的构造方法:

・public view(Context context)       当在代码中创建对象时会被调用

・public View (Context context, AttributeSet attrs)

官方的文档是:

Constructor that is called when inflating a view from XML. This is called when a view is being constructed from an XML file, supplying attributes that were specified in the XML file. This version uses a default style of 0, so the only attribute values applied are those in the Context's Theme and the given AttributeSet

大致应该是这个方法是通过xml文件来创建一个view对象的时候调用。很显然xml文件一般是布局文件,就是现实控件的时候调用,而布局文件中免不了会有属性的设置,如android:layout_width等,对这些属性的设置对应的处理代码也在这个方法中完成。

两个参数

Context          The Context the view is running in, through which it can access the current theme, resources, etc.

Attrs              The attributes of the XML tag that is inflating the view

・public View (Context context, AttributeSet attrs,int defStyle)

Perform inflation from XML and apply a class-specific base style. This constructor of View allows subclasses to use their own base style when they are inflating. For example, a Button class's constructor would call this version of the super class constructor and supply R.attr.buttonStyle fordefStyle; this allows the theme's button style to modify all of the base view attributes (in particular its background) as well as the Button class's attributes.

看的不太懂,没用到,下放一下吧额

这就是为什么要添加上面的两个构造方法的原因。

本文来源:http://www.bbyears.com/asp/89162.html

热门标签

更多>>

本类排行