自定义组合控件

在编写安卓程序的时候,针对同一个布局(xml)反复使用的情况下,为了增加代码的重用性,我们需要做一定的封装,其中就包括两种情况:

 

 1. 布局内填充:

   继承ViewGroup子类(直接继承ViewGroup需要重写它的onLayout方法),并在构造方法中完成自定义view布局的内填充,这种适合于已有的控件进行组合能得到符合实际开发的目的。如:

 

编写自定义组合控件的布局图 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >

<TextView
android:id="@+id/tv_first"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
/>


<CheckBox
android:id="@+id/checkbox_second"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
/>

</LinearLayout>

 

 

在ViewGroup的继承类中,将布局进行内填充

package com.example.views.view;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.example.views.R;

public class CustomView extends RelativeLayout {

private TextView tv_first;
private CheckBox cb_second;
public CustomView(Context context) {
this(context,null);
}

public CustomView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}

public CustomView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
View view = LayoutInflater.from(context).inflate(R.layout.view_custom,this,true);
tv_first = (TextView) view.findViewById(R.id.tv_first);
cb_second = (CheckBox) findViewById(R.id.checkbox_second);
}

public void setText(String content){
tv_first.setText(content);
}

public boolean isSelected(){
return cb_second.isChecked();
}

public void setSelected(boolean isCheck){
cb_second.setChecked(isCheck);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
cb_second.setChecked(!cb_second.isChecked());
return super.onTouchEvent(event);
}

/**
* 这个方法是ViewGroup子类专有方法,表示是否拦截事件
* true 表示拦截 也就是说Touch事件不交由viewgroup中的控件处理,保证checkbox的点击事件不会执行
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return true;
}
}

 

在activity_main.xml文件中,只需要控件的简单声明:

<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
>

<com.example.views.view.CustomView
android:id="@+id/customView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" >
</com.example.views.view.CustomView>

</RelativeLayout>

 

  2. 完全自定义控件: 当原的控件不能满足自身的需要我们就需要自定义控件,然后控件分为两种大的方向,一个是View类型,另一个是ViewGroup类型。如果是View类型的话,就需要重写它的onMeasure(), onDraw(Canvas canvas),甚至需要重写OnTouchEven()来处理特殊的触摸事件,比如说,TextView实现滑动换文字内容,就需要处理Touch事件。 如果是ViewGroup类型的话,就可能需要重现onMeasure() onLayout(),而此时的onDraw方法大多情况下就不需要关心了,一般有里面view自行调用自己的onDraw方法。更值得一提的是,在自定义控件的时候,我们可能需要将控件的属性直接写在activity_main.xml(代替所有的布局文件)文件中,免去用代码在进行控件属性的

设置,这个时候,自定义属性就派上了用场,如:

 

 res/values/attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="customview">
<attr name="backColor" format="reference|color"/>
<attr name="outColor" format="reference|color"/>
<attr name="ringWidth" format="reference|dimension"/>
</declare-styleable>
</resources>

 

View控件代码

package com.example.customview.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.widget.ImageView;

import com.example.customview.R;

public class CustomView extends ImageView {

private int backColor;
private int outColor;
private float ringWidth;

private int mWidth;

public CustomView(Context context) {
this(context, null);
}

public CustomView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.customview);
backColor = typedArray.getColor(R.styleable.customview_backColor, Color.RED);
outColor = typedArray.getColor(R.styleable.customview_outColor,Color.BLUE);
ringWidth = typedArray.getDimension(R.styleable.customview_ringWidth, 0);
}

public CustomView(Context context, AttributeSet attrs) {
this(context, attrs, 0);

}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = Math.min(MeasureSpec.getSize(widthMeasureSpec),
MeasureSpec.getSize(heightMeasureSpec));
setMeasuredDimension(mWidth, mWidth);
}

@Override
protected void onDraw(Canvas canvas) {
Paint paint = new Paint();
paint.setColor(outColor);
canvas.drawCircle(mWidth/2, mWidth/2,mWidth/2, paint);
paint.setColor(backColor);
canvas.drawCircle(mWidth/2, mWidth/2,mWidth/2-ringWidth, paint);
}
}

 

//布局文件:

<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res/com.example.customview"
android:layout_width="match_parent"
android:layout_height="match_parent" >

<com.example.customview.view.CustomView
android:id="@+id/customView1"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
app:backColor="#f00"
app:outColor="#0f0"
app:ringWidth="5dp"
/>

</RelativeLayout>

 

 

 

 

  

posted on 2016-03-14 23:04  2013551627  阅读(179)  评论(0编辑  收藏  举报