Android自定义View的实现小结

本文详细介绍了如何在Android中自定义View控件,包括继承View类、添加构造方法、处理XML属性以及实现背景颜色的自定义。通过实例演示了自定义View的基本步骤和注意事项,旨在帮助开发者掌握自定义UI组件的技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

很多时候系统自带的 View 满足不了设计的要求,就需要自定义 View 控件。自定义 View 首先要实现一个继承自 View 的类。添加类的构造方法, override 父类的方法,如 onDraw ,( onMeasure )等。如果自定义的 View 有自己的属性,需要在 values 下建立 attrs.xml 文件,在其中定义属性,同时代码也要做修改。

一个简单的例子:

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

package com.example.xhelloworld;

import android.content.Context;

import android.widget.TextView;

publicclass MyViewextends 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;

publicclass NewViewextends Activity {

   @Override

   publicvoid onCreate(Bundle savedInstanceState) {

       super.onCreate(savedInstanceState);

       //setContentView(R.layout.activity_newview);

       setContentView(new MyView(this));

       

   }

   @Override

   publicboolean onCreateOptionsMenu(Menu menu) {

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

       returntrue;

   }

}

运行后的结果为:

 

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

@Override

   protectedvoid 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)中也需要进行如下操作:

<com.example.xhelloworld.NewView

       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

   publicvoid onCreate(Bundle savedInstanceState) {

       super.onCreate(savedInstanceState);

       setContentView(R.layout.main);

       //setContentView(new MyView(this));

显示的效果同上图。

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

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

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

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

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

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

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

<resources> 

   <declare-styleablename="MyView"> 

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

   <attrname="textSize"format="dimension"/> 

   </declare-styleable> 

</resources>

然后在布局文件中完成:

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

<com.example.xhelloworld.MyView 

      android:layout_width="fill_parent" 

      android:layout_height="wrap_content"   

      my:textColor="#FFFFFFFF"   

      my:textSize="22dp" 

    /> 

注:这步我在实现的时候出错,问题是显示找不到属性textColortextSize,这奇怪的错误。解决方法是,在写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 viewContext 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文件一般是布局文件,就是现实控件的时候调用,而布局文件中免不了会有属性的设置,如androidlayout_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 attrsint 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.

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

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

 

自定义View会用到TypedArrayattrs.xmlAttributeSet知识

先说一下attrs.xml文件。这个文件定义了自定义View的属性的信息,包括属于哪个控件属性的名称,属性的类型。下面是一个普通的attrs.xml的内容

<resources>

<declare-styleable name = “MyView”>

    <attr name = “textColor” format = “color”></attr>

<attr name = “textSize” format = “dimension”/>

</declare-styleable>

</resources>

其中标签declare-styleablename属性代表了接下来定义的属性的所属控件(只是用来区分不同declare-styleable的代号而且,不一定非要和属性相关的控件的名称一致)。标签attr就是用来的定义具体的属性,name代表属性名,format代表属性的类型。

Attrs.xml文件中属性类型format值的格式

引用型reference

定义:

<attr name = “background” format = “reference” />

使用:

Tools:background = “@drawable/图片ID”

颜色型color

定义:<attr name = “textColor” format = “color” />

使用:tools:textColor = “#ffffff”

布尔型boolean

定义:<attr name = “focusable” format = “boolean” />

使用:tools: focusable = “true”

尺寸型dimension

定义:<attr name = “layout_width” format = “dimension” />

使用:tools: layout_width = “42dip”

浮点型float

定义:<attr name = “fromAlpha” format = “float” />

使用:tools: fromAlpha = “1.0”

整型integer

定义:<attr name = “frameDuration” format = “integer” />

使用:tools: frameDuration = “100”

字符串string

定义:<attr name = “apiKey” format = “string” />

使用:tools: apiKey = “dsegergegasefwg”

百分数fraction

定义:<attr name = “pivotX” format = “fraction” />

使用:tools: pivotx = “200%”

枚举型enum

< attr name="orientation">

  < enum name="horizontal" value="0" />

  < enum name="vertical" value="1" />

< /attr>

使用:android:orientation = "vertical"

标志位、位或运算,格式如下:

< attr name="windowSoftInputMode">

  < flag name = "stateUnspecified" value = "0" />

  < flag name = "stateUnchanged" value = "1" />

  < flag name = "stateHidden" value = "2" />

  < flag name = "stateAlwaysHidden" value = "3" />

  < flag name = "stateVisible" value = "4" />

  < flag name = "stateAlwaysVisible" value = "5" />

  < flag name = "adjustUnspecified" value = "0x00" />

  < flag name = "adjustResize" value = "0x10" />

  < flag name = "adjustPan" value = "0x20" />

  < flag name = "adjustNothing" value = "0x30" />

< /attr>

XML中使用:

android:windowSoftInputMode = "stateUnspecified | stateUnchanged | stateHidden">

属性定义可以指定多种类型:

定义:< attr name = "background" format = "reference|color" />

使用:android:background = "@drawable/图片ID|#00FF00"

TypedArray

Context类的obtainStyledAttributes方法一起使用,作为一个不同类型的数据的容器使用。使用是如:

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

这句一般是使用在自定义View的构造方法中的,其中attrs是构造方法的形参,而R.styleable.MyView是和attrs.xml相关的。MyViewattrs.xmldeclare-styleablename属性的值。如果这个自定义Viewattrs.xml文件中对应的declare-styleablename属性值为A,那么这里就写R.styleable.A

其中包括很多方法,用来获取这个容器中包含的值

·getColor  获取颜色值

·getDimension   获取尺寸值

这些方法一般都有这两个参数int index, int defValue。其中index为用来查找属性的检索值。如果实在attrs.xml文件中定义的属性,就是R.styleable.xxxx_yyyyXxxx代表declare-styleablename值,yyyy代表attrname值。

defValue代表默认值,即如果在xml文件中没有设置,可以使用默认值来进行设置。

AttributeSet是一个属性的集合,与一个在XML文件中的标签相联系。如在自定义View中,构造方法中会有一个AttributeSet类型的参数,这个参数就和XML中定义的自定义View相联系的。一般不需要直接使用它。

 

转自:http://blog.chinaunix.net/uid-26885609-id-3479675.html

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值