自定义控件之定义UI模板

来源:互联网 发布:芜湖经济数据 编辑:程序博客网 时间:2024/04/28 03:11

自定义控件之定义UI模板

前言:

            以前学过一点自定义控件,但是好久没有用,早都忘记了,前几天抽空看了个视频,在慕课网上的,链接是http://www.imooc.com/learn/247  就跟着这个视频重新学了一遍,俗话说好记性不如烂笔头。所以就把里面的步骤都一步一步的记录了下来,给自己以后做参考。也希望能给有需要的人一点帮助:

主要包括以下步骤:

 

一:设计需要的属性

value文件夹下,建立一个arrts.xml的文件

声明declare-styleable属性,来告诉系统,这个是我们自定义的属性。

定义attr标签,给每个属性起个名字和对应的格式

name是表示你定义的属性的名字。format表示我们在xml中引用的类型,

 

例如:       

<attr name="title" format="string"/> 就表示定义一个属性名为title,用来表示标题。类型是string类型的,给这个属性赋值的时候,就可以引用string.xml文件中的值了

<attr name="titleTextSize"format="dimension" /> 定义属性为titleTextSize用来表示标题字体的大小,类型是尺寸,给这个属性赋值的时候,就可以使用R.dimen.

<attr name="titleTextColor"format="color" />  定义属性名为titleTextColor,用来表示标题文字颜色,类型是color,就可以使用color.xml文件中的数据了

 

自定义的attr.xml文件代码:

 

<?xml version="1.0" encoding="utf-8"?>

<resources>

 

    <!--通过声明declare-styleable 属性,来告诉系统,这个是我们自定义的属性,-->

   <declare-styleable name="Topbar">

        <!--定义attr标签,来定义第一个属性,为名字为title,用来表示标题的文字,-->

        <attr name="title"format="string" />

        <attrname="titleTextColor" format="color" />

 

        <attrname="leftText" format="string" />

        <!--定义背景,不仅仅是color属性,还定义来一个reference属性,因为我们引用背景的时候,不仅仅可以使用十六进制的颜色代码,@color-->

        <!--还可以引用资源中的一个文件 @drawbable-->

        <attrname="leftBackgroud" format="reference|color" />

        <attrname="leftTextColor" format="color" />

 

        <attrname="rightText" format="string" />

        <attrname="rightBackgroud" format="reference|color" />

        <attrname="rightTextColor" format="color" />

 

   </declare-styleable>

</resources>

 

 

 

二:实现一个我们的View

自定义的类名为TopBar,继承RelativeLayout ,并重写了其中一个构造方法,RelativeLayout中有三个构造方法的,而且这三个中没有无参构造函数,所以根据java语法,是至少需要重写其中一个的,我们这里必须要重写的就是带有AttributeSet这个参数的构造函数,因为这个参数就是我们需要的属性

即:

    publicTopBar(Context context, AttributeSet attrs) {

        super(context,attrs);

}

在构造方法中,我们需要做的又以下几件事情

1.通过obtainStyledAttributes()根据上下文获得TypedArray对象

obtainStyledAttributes()接受两个参数,

第一个参数就是构造函数中的AttributeSet对象,

后一个就是我们在xml文件中定义的属性集合,即attr.xml文件,

系统就是通过这个方法,把我们在xml文件中定义的属性值映射到属性集合中去,返回了一个TyperdArray对象ta,这样,我们就可以通过ta取得相应的属性的值,

 

2.从TypedArray中取得相应的值赋给相应的变量

其实这一步就可以理解是这样的,定义一个textView,在定义该Textview中,使用到了android:text=“自定义控件”;那么我们通过ta.getString(属性名)就得到了相应的值,还记得我们定义的属性的format格式吗,这个时候就用到了,取出该属性值就可以通过相应的方法了

属性名的规定:R.styleable.属性集合的名_属性名

例如:R.styleable.Topbar_leftTextColor 就表示Topbar下面的 leftTextColor属性

 

定义的是format类型的变量,就可以通过相应的方法获取

例如:

leftTextColor =ta.getColor(R.styleable.Topbar_leftTextColor, 0);// format类型是color,默认的是0

leftBackground =ta.getDrawable(R.styleable.Topbar_leftBackground);//format类型是Drawable

leftText = ta.getString(R.styleable.Topbar_leftText);//format类型是字符串

titleTextSize =ta.getDimension(R.styleable.Topbar_titleTextSize, 0f);//format类型是float

 

记得最后要调用TypedArray的recycle()方法,对象进行回收,避免浪费资源,避免由于缓存引起的一些错误

 

代码如下:

 

TypedArray ta =context.obtainStyledAttributes(attrs, R.styleable.Topbar);

 

leftTextColor =ta.getColor(R.styleable.Topbar_leftTextColor, 0);

leftBackground =ta.getDrawable(R.styleable.Topbar_leftBackground);

leftText =ta.getString(R.styleable.Topbar_leftText);

//为左边和右边的button找到了我们自定义的属性的值

rightTextColor = ta.getColor(R.styleable.Topbar_rightTextColor,0);

rightBackground =ta.getDrawable(R.styleable.Topbar_rightBackground);

rightText =ta.getString(R.styleable.Topbar_rightText);

 

       //定义位子的大小,使用getDimension

titleTextSize =ta.getDimension(R.styleable.Topbar_titleTextSize, 0f);

titleTextColor =ta.getColor(R.styleable.Topbar_titleTextColor, 0);

title =ta.getString(R.styleable.Topbar_title);

 

ta.recycle();//对象进行回收,避免浪费资源,避免由于缓存引起的一些错误

 

3.实例化控件

自定义的ui模板是什么样的,自己心里肯定有数,有几个TextView,几个Button,等,肯定是事先知道的,name在这个时候,你就需要实例化这些控件

例如在这个布局中,需要两个Button,左边一个,右边一个,中间是一个TextView,那么就需要实例化这三个控件

leftButton = new Button(context);

      rightButton = new Button(context);

      tvTitle = new TextView(context);

4.给控件赋值,

因为之前已经通过TypedArray得到自定义属性的值了,这个时候就需要给相应的控件进行赋值,这就和我们普通的设置值没有什么两样了,这就没什么好说的了

//对左边button进行一些设置

       leftButton.setTextColor(leftTextColor);

       leftButton.setText(leftText);

       leftButton.setBackground(leftBackground);

 

       //对右边button进行的一些设置

       rightButton.setTextColor(rightTextColor);

       rightButton.setText(rightText);

       rightButton.setBackground(rightBackground);

 

       //对title进行的一些设置

       tvTitle.setTextColor(titleTextColor);

       tvTitle.setText(title);

       tvTitle.setTextSize(titleTextSize);

 

       tvTitle.setGravity(Gravity.CENTER);//设置标题文字居中显示

 

       setBackgroundColor(0xFFFFCC1F);//设置背景颜色

 

5.排版

控件也定义好了,相应的值也赋上去了,那么现在就需要把这些控件放到自定义UI模板上去了

这就需要用到一个类Layoutparams,设置该控件的相应参数。通过addView方法,把每个控件添加到模板布局上去。

 

通过Layoutparams 方式把一个控件添加到VIewGroup中 

leftParams = new LayoutParams(LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);

leftParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT,TRUE);//这里的true并不是我们通常说的真假,而是RelativeLayout定义的一个常量,RelativeLayout.TRUE,表示-10表示false,或者其它ViewId,如果有其他view的id,就表示是相对于该id的布局

 

//这样我们就定义了一个属性,

addView(leftButton, leftParams);//这样就把leftButton,以leftParams的形式加入到了viewGroup中了

 

rightParams = new LayoutParams(LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);

rightParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT,TRUE);

addView(rightButton, rightParams);

 

titleParams = new LayoutParams(LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.MATCH_PARENT);

titleParams.addRule(RelativeLayout.CENTER_IN_PARENT,TRUE);

addView(tvTitle, titleParams);

这样我们就初步定义了一个自定义UI模板。定义好,之后,我们就开始使用这个UI模板

 

 

三:引用我们的View

1.引用第三方命名空间

怎么使用我们自定义的模板呢?

想想我们在使用Android提供的控件的时候,想定义该控件的某个属性时候,通常就是 android:****=“”   这样的格式的,这个android是什么呢?按住ctrl,鼠标结果指向了布局根节点的  xmlns:android=http://schemas.android.com/apk/res/android

这个xmlns  其实就是xml的命名空间,我理解的是和我们写java类中的导入包是一样的吧,如果想引用我们自己定义的UI模板,那么就需要把我们自定义的模板类引用到该布局中,Android中引用第三方的命名空间,需要

   xmlns:custom="http://schemas.android.com/apk/res-auto"

 

其中只有custom是可以自定义的,就是你定义的名字,其他都是规定死的,

但是在不同的IDE 上,语法稍有不同:eclipse上最后面需要跟上类全名(没测试,我用的是studio,没有添加类全名,也可以使用)

Android Studio     "http://schemas.android.com/apk/res-auto"

eclipse           “http://schemas.android.com/apk/res-auto /类全名”

2.使用自定义模板

一切就绪,我们就可以像使用一般的控件那样使用我的自定义模板了,在我们自定义的模板中,也可以使用Android自带的一些属性的,例如id,layout_width,layout_height ,这些是Android自带的属性,开头都是以android开头的,而我们自定义的属性,开头都是之前定义的custom,我们都知道,引用自定义的控件,就需要使用类全名的,整体代码如下:

 

<com.example.hoyouly.mytopbar.TopBar

       android:id="@+id/topbar"

       android:layout_width="wrap_content"

       android:layout_height="50dp"

 

       custom:leftBackground="#0000ff"

       custom:leftText="后退"

       custom:leftTextColor="#FFFFFF"

 

       custom:rightBackground="#0000ff"

       custom:rightText="测试"

       custom:rightTextColor="#FFFFFF"

 

       custom:title="自定义标题"

       custom:titleTextColor="#ff0000"

       custom:titleTextSize="10sp"

       />

这样,我们就可以在类中像使用一般的控件那样使用我们自定义的模板了

       topBar = (TopBar) findViewById(R.id.topbar);

3.更多功能设置

当然,我们还可以对我们的自定义模板进行更多的功能设置。例如设置按钮是否隐藏,等

这样我们就需要对外提供一些方法

例如:设置左按钮是否隐藏:

 public void setLeftButtonIsVisable(boolean flag){

       if(flag){

           leftButton.setVisibility(View.VISIBLE);

       }else{

           leftButton.setVisibility(View.INVISIBLE);

       }

    }

 

这样,就可以在主类中使用了

       topBar.setLeftButtonIsVisable(false); 坐按钮隐藏

 

四:接口回调机制:

为了使我们UI模板更加完美,增加动态响应效果,就需要让我们UI模板设计的像普通的控件能够处理点击,当然,这些可以在我们模板中处理,可是如果每次都再模板中处理,那么就失去了模板的作用,那该怎处理这些点击事件呢,这就需要接口回调机制的帮助了。

在我们定义一个普通Button的点击事件的时候,通常是调用setOnClickListener()方法,里面接受的是一个接口对象,实现里面的方法,从而实现接口回调。虽然我不知道你要做什么事情,但是你只要实现这个接口就行

举个不知道是否合适的例子,你想找朋友借车,朋友说,我不想知道你干嘛去,但是你必须得帮我把这包东西送给某某才行,不让我就不借给你。

同样的,你要像设置点击事件,Button不想知道,也不愿意知道你点击他要干嘛,但是你必须要实现我定义个规则才行

这里定义接口回调机制其实也挺简单的;

只需要三步骤就可以了,

1.  定义一个接口

首先需要定义一个接口,在Topbar中定义一个接口TopBarClickListener

这里我们就定义了两个方法,点击左按钮和右按钮

public interface  TopBarClickListener{

       public void leftClick();//点击左按钮

       public void rightClick();//点击右按钮

}

2.  对外提供方法进行设置

 在TopBar中提供设置接口的方法,

public voidsetOnTopbarClickListener(TopBarClickListener topbarClickListener){

       this.topBarClickListener=topbarClickListener;

    }

3.  对内调用该接口中的方法

在Topbar处理左右按钮的点击事件的时候,直接调用相应的方法就可以

leftButton.setOnClickListener(newOnClickListener() {

           @Override

           public void onClick(View view) {

               topBarClickListener.leftClick();

           }

       });

       rightButton.setOnClickListener(new OnClickListener() {

           @Override

           public void onClick(View view) {

               Toast.makeText(context,"right Button",Toast.LENGTH_LONG).show();

               topBarClickListener.rightClick();;

           }

       });

 

 

那么我们在使用点击事件的时候,只需要传递给TopBar一个实现TopBarClickListener接口的对象就可以了,至于这个接口中做的什么事情,就没有必要管了,

topBar.setOnTopbarClickListener(newTopBar.TopBarClickListener() {

           @Override

           public void leftClick() {

               Toast.makeText(MainActivity.this, "leftButton",Toast.LENGTH_LONG).show();

            }

 

           @Override

           public void rightClick() {

               Toast.makeText(MainActivity.this, "leftButton",Toast.LENGTH_LONG).show();

           }

       });

这样就完成了一个接口回调了。

五:总结

不知道的是,看完这个视频,自己学到的自定义UI模板的步骤:最主要的是又一次加深理解了接口回调机制。记录一下。自己洋洋洒洒写了这么多,很少会有人会认真看完吧。

0 0
原创粉丝点击