自定义属性+接口回调Demo
自定义属性:
参考:原文写的很详细,在此,我收录了一些重点作为笔记
http://www.cnblogs.com/lonelyDog/archive/2012/06/28/2568519.html
自定义属性的实现流程:
1、在values目录下定义一个attrs.xml
2、在对应的类文件里生成某些组件
3、在layout布局文件里为这些属性赋值。
实现第一步:
在res/values/attr.xml中定义。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 这里的MyView属性并不是一定要和自定义组件类名相同,只是为了好区分对应类的属性而已 -->
<declare-styleable name = "MyView">
<attr name= "TEXTCOLOR" format= "color" />
<attr name= "TEXTSIZE" format= "dimension" />
<attr name= "recWidth" format= "dimension" />
<attr name= "recHeight" format= "dimension" />
</declare-styleable>
</resources>
知识点:
1、declare-styleable
定义一个styleable对象,每个styleable对象就是一组attr属性的集合
2、attr子元素:
定义具体的属性
1.reference:参考指定Theme中资源ID,这个类型意思就是你传的值可以是引用资源
2.string:字符串,如果你想别人既能直接写值也可以用类似”@string/test”引用资源的方式,可以写成format=”string|reference”
3.Color:颜色
4.boolean:布尔值
5.dimension:尺寸值
6.float:浮点型
7.integer:整型
8.fraction:百分数
9.enum:枚举 ,如果你提供的属性只能让别人选择,不能随便传入,就可以写成这样
<attr name="language">
<enum name="china" value="1"/>
<enum name="English" value="2"/>
</attr>
10.flag:位或运算
实现第二步
自定义组件类
重点是获取自定义属性,关键代码如下:
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MyView);
textsize = array.getDimension(R.styleable.MyView_TEXTSIZE, 30);// 放在在xml中未定义,设置默认值
完整代码如下
public class MyView extends ViewGroup implements OnClickListener{
private Paint myPaint;
private int textColor;
private int recWidth;
private int recHeight;
private float textsize;
private ImageView imgView;
public MyView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyView(Context context) {
this(context, null);
}
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
myPaint = new Paint();
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MyView);
textsize = array.getDimension(R.styleable.MyView_TEXTSIZE, 30);// 放在在xml中未定义,设置默认值
recHeight = (int) array.getDimension(R.styleable.MyView_recHeight, 30);// 放在在xml中未定义,设置默认值
recWidth = (int) array.getDimension(R.styleable.MyView_recWidth, 30);// 放在在xml中未定义,设置默认值
textColor = array.getColor(R.styleable.MyView_TEXTCOLOR, Color.YELLOW);
myPaint.setColor(textColor);
myPaint.setTextSize(textsize);
array.recycle();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
myPaint.setColor(Color.RED);
myPaint.setStyle(Style.FILL);
canvas.drawRect(new Rect(10, 40, 100+recWidth, 100+recHeight), myPaint);
myPaint.setColor(textColor);
canvas.drawText("hellohelooe", 10, 100, myPaint);
}
@Override
public void onClick(View view) {
iMyView.rectClick(view);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int count = getChildCount();
for(int i = 0; i< count;i++){
measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int arg1, int arg2, int arg3, int arg4) {
if(changed){
imgLayout();
}
}
private void rotateCButton(View v, float start, float end, int duration) {
RotateAnimation anim = new RotateAnimation(start, end, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
anim.setDuration(duration);
anim.setFillAfter(true);//图形留在动画停止处
v.startAnimation(anim);
}
private void imgLayout() {
imgView = (ImageView) getChildAt(0);
imgView.setOnClickListener(this);
int width = imgView.getWidth();
int height = imgView.getHeight();
imgView.layout(0, 0, 300+width, 400+height);
}
private IMyView iMyView;
public void setIMyView(IMyView iMyView) {
this.iMyView = iMyView;
}
public interface IMyView{
public void rectClick(View view);
}
}
实现第三步
在布局中的设置
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:huqing="http://schemas.android.com/apk/res/com.example.typedarraydemo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/textView1"
android:layout_width="fill_parent"
android:layout_height="40dp"
android:gravity="center"
android:text="系统的控件" />
<com.example.typedarraydemo.demo1.MyView
android:id="@+id/ad_myView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
huqing:TEXTCOLOR="#42E61A"
huqing:TEXTSIZE="120px"
huqing:recHeight="500px"
huqing:recWidth="500px" >
<ImageView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:src="@drawable/ic_launcher" />
</com.example.typedarraydemo.demo1.MyView>
</LinearLayout>
**在XML使用该组件的时候一定要为该自定义组件设置一个命名空间[xmlns:myandroid=”http://schemas.android.com/apk/res/cn.com.androidtest”],不然组件属性设置不了
命名空间写法:xmlns:空间名=”http://schemas.android.com/apk/res/自定义组件所在顶级包名”**
以上就实现了自定义属性的使用了。接下来实现接口定义。
在自定义View中加入
private IMyView iMyView;
public void setIMyView(IMyView iMyView) {
this.iMyView = iMyView;
}
public interface IMyView{
public void rectClick(View view);
}
调用的Activity代码如下
public class Demo1 extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.acty_demo1);
MyView myView = (MyView)findViewById(R.id.ad_myView);
myView.setIMyView(new IMyView() {
@Override
public void rectClick(View view) {
Toast.makeText(Demo1.this, "这里使用到了接口回调", Toast.LENGTH_LONG).show();
}
});
}
}
自定义View方法:
onFinishInflate() 回调方法,当应用从XML加载该组件并用它构建界面之后调用的方法
onMeasure() 检测View组件及其子组件的大小
onLayout() 当该组件需要分配其子组件的位置、大小时
onSizeChange() 当该组件的大小被改变时
onDraw() 当组件将要绘制它的内容时
onKeyDown 当按下某个键盘时
onKeyUp 当松开某个键盘时
onTrackballEvent 当发生轨迹球事件时
onTouchEvent 当发生触屏事件时
onWindowFocusChanged(boolean) 当该组件得到、失去焦点时
onAtrrachedToWindow() 当把该组件放入到某个窗口时
onDetachedFromWindow() 当把该组件从某个窗口上分离时触发的方法
onWindowVisibilityChanged(int): 当包含该组件的窗口的可见性发生改变时触发的方法