前言:

在Android日常开发过程中难免会遇到Android标准控件库中没有满足要求的,这时候就需要自定义控件。一个好的自定义控件应当和Android本身提供的控件一样,封装了一系列的功能以供开发者使用,不仅具有完备的功能,也优化对内存和CPU的使用。

指标:

个人自定义控件应该满足下面一些指标:

1. 应当遵守Android标准的规范(命名,可配置,事件处理等)。
2. 在XML布局中可配置控件的属性。
3. 对交互应当有合适的反馈,比如touch,click等。
4. 具有兼容性, Android版本很多,应该具有广泛的适用性。
好在Android已经提供了一系列基础控件和xml属性来帮助我们进行自定义控件的创建

1.View的子类

在Android, 几乎所有的控件均继承自View,你也可以直接继承View也可以继承其他的控件比如ImageView等,也可能对这些控件进行组合。具体定义时需要至少提供一个构造函数,其中Context和AttributeSet作为参数,如下:

public LevelMenuItem(Context context, AttributeSet attrs) {    super(context, attrs);}
2. 自定义属性
优秀的自定义控件需要支持可添加xml来配置属性和风格。 实现步骤如下:
1) Style XML 中添加自定义属性
2) 在xml的中,指定属性的名称与值类型
3) 在view中获取xml中的值
4) 将获取的值应用到view中
如sytle.xml中添加:
<declare-styleable name="LevelMenuItem">    <attr name="text" format="string" />    <attr name="text_color" format="color"/>    <attr name="text_size" format="dimension" />    <attr name="image_src" format="reference"/>    <attr name="image_bg" format="reference"/>    <attr name="image_alpha" format="integer" />    <attr name="image_height" format="dimension"/>    <attr name="image_width" format="dimension" />declare-styleable>
layout中设置属性值:
   
<com.example.qinghua_liu.myapplication.LevelMenuItem    android:id="@+id/item0"    android:layout_below="@+id/mybutton1"    android:layout_width="70dp"    android:layout_height="80dp"    linc:text="杭州"    linc:text_size="6sp"    linc:text_color="#80fa8072"    linc:image_src="@drawable/orange_button_selector"    linc:image_alpha="128"    linc:image_height="48dp"    linc:image_width="48dp"    />
3. 应用属性值
之后 在自定义控件中,就可以读这些值,并应用到控件上了,需要注意的是, TypeArray使用完毕后需要销毁,不然会发生内存泄露
   
mTextView = (TextView) findViewById(R.id.tv_item);String textString = typedArray.getString(R.styleable.LevelMenuItem_text);int textColor = typedArray.getColor(R.styleable.LevelMenuItem_text_color,        0xffffffff);float textSize = typedArray.getDimension(R.styleable.LevelMenuItem_text_size,        20);mTextView.setText(textString);mTextView.setTextColor(textColor);mTextView.setTextSize(textSize);
4. 设置方法与事件回调 自定义它只能在view初始化的时候被应用到控件中。 为了添加更加灵活的行为,就需要自定义方法:
   
public int getTextSize() {    return this.mTextSize;}

public void setTextSize(int textSize) {  
     this.mTextSize=textSize;
     invalidate();     requestLayout();
}
invalidate()和requestLayout(), 保证了view能及时的更新。在你的自定义View中,如果有属性被改变并且需要立即生效时,
就需要调用这个方法。 这样系统会立即重新绘制view。 同样的,如果view的尺寸或者形状发生了变化,也必须调用requestLayout()。
实战
下面结合代码来尝试自定义组合控件的实现:
素材:
找两张图片素材,做一个圆形的按钮,一张正常显示,一点按下时显示:
Style属性:
<declare-styleable name="LevelMenuItem">    <attr name="text" format="string" />    <attr name="text_color" format="color"/>    <attr name="text_size" format="dimension" />    <attr name="image_src" format="reference"/>    <attr name="image_bg" format="reference"/>    <attr name="image_alpha" format="integer" />    <attr name="image_height" format="dimension">attr>    <attr name="image_width" format="dimension" />declare-styleable>
   
定义ImageView selector xml
drawable/selector
   
<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android" >    <item android:state_pressed="true"        android:drawable="@drawable/button_push"/>    <item android:drawable="@drawable/orange_button"/>selector>


layout:
level_menu_item.xml(图片加文字的组合按钮)
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:gravity="center"    android:orientation="vertical" >    <ImageView        android:layout_gravity="center_horizontal"        android:id="@+id/image_item"        android:layout_width="fill_parent"        android:layout_height="fill_parent"        android:scaleType="fitCenter"        />    <TextView        android:id="@+id/tv_item"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:gravity="center_horizontal"        android:textColor="#23ffffff"        android:textSize="25sp"        android:layout_gravity="center_horizontal"        />LinearLayout>
level_menu.xml:(控件组,包含三个上面的控件)
   
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:linc="http://schemas.android.com/apk/res-auto"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:orientation="horizontal">    <com.example.qinghua_liu.myapplication.LevelMenuItem        android:id="@+id/item1"        android:layout_width="70dp"        android:layout_height="80dp"        linc:text="天气"        linc:text_size="6sp"        linc:text_color="#80fa8072"        linc:image_src="@drawable/orange_button_selector"        linc:image_alpha="128"        linc:image_height="48dp"        linc:image_width="48dp"        />    <com.example.qinghua_liu.myapplication.LevelMenuItem        android:id="@+id/item2"        android:layout_marginLeft="20dp"        android:layout_width="70dp"        android:layout_height="80dp"        linc:text="新闻"        linc:text_size="6sp"        linc:text_color="#ffeee8aa"        linc:image_src="@drawable/orange_button_selector"        linc:image_alpha="255"        linc:image_height="48dp"        linc:image_width="48dp"        />    <com.example.qinghua_liu.myapplication.LevelMenuItem        android:id="@+id/item3"        android:layout_marginLeft="20dp"        android:layout_width="70dp"        android:layout_height="80dp"        linc:text="景区"        linc:text_size="6sp"        linc:text_color="#80cd853f"        linc:image_src="@drawable/orange_button_selector"        linc:image_alpha="128"        linc:image_height="48dp"        linc:image_width="48dp"        />LinearLayout>
   
   
LevelMenuItem.java
public class LevelMenuItem extends LinearLayout {    private TextView mTextView = null;    private ImageView mImageView = null;    public LevelMenuItem(Context context) {        super(context);    }    public LevelMenuItem(Context context, AttributeSet attrs) {        super(context, attrs);        LayoutInflater layoutInflater = (LayoutInflater) context.                getSystemService(Context.LAYOUT_INFLATER_SERVICE);        layoutInflater.inflate(R.layout.level_menu_item, this);        TypedArray typedArray = context.obtainStyledAttributes(attrs                , R.styleable.LevelMenuItem);        initWidget(typedArray);    }    private void initWidget(TypedArray typedArray) {        mTextView = (TextView) findViewById(R.id.tv_item);        String textString = typedArray.getString(R.styleable.LevelMenuItem_text);        int textColor = typedArray.getColor(R.styleable.LevelMenuItem_text_color,                0xffffffff);        float textSize = typedArray.getDimension(R.styleable.LevelMenuItem_text_size,                20);        mTextView.setText(textString);        mTextView.setTextColor(textColor);        mTextView.setTextSize(textSize);        mImageView = (ImageView) findViewById(R.id.image_item);        int imageHeight = (int) typedArray.getDimension(R.styleable.LevelMenuItem_image_height, 25);        int imageWidth = (int) typedArray.getDimension(R.styleable.LevelMenuItem_image_width, 25);        int imageSrc = typedArray.getResourceId(R.styleable.LevelMenuItem_image_src, 0);        int imageBg = typedArray.getResourceId(R.styleable.LevelMenuItem_image_bg, 0);        int imageAlpha = typedArray.getInt(R.styleable.LevelMenuItem_image_alpha, 255);        mImageView.setAlpha(imageAlpha);        mImageView.setImageResource(imageSrc);        mImageView.setBackgroundResource(imageBg);        LayoutParams layoutParams = new LayoutParams(imageWidth, imageHeight);        mImageView.setLayoutParams(layoutParams);        typedArray.recycle();    }    /**     * 设置此控件的文本     *     * @param text     */    public void setText(String text) {        mTextView.setText(text);    }    /**     * 设置文字颜色     *     * @param textColor     */    public void setTextColor(int textColor) {        mTextView.setTextColor(textColor);    }    /**     * 设置字体大小     *     * @param textSize     */    public void setTextSize(int textSize) {        mTextView.setTextSize(textSize);    }    /**     * 设置图片     *     * @param resId     */    public void setImageResource(int resId) {        mImageView.setImageResource(resId);    }    /**     * 设置图片背景     */    public void setBackgroundResource(int resId) {        mImageView.setBackgroundResource(resId);    }    /**     * 设置图片的不透名度     *     * @param alpha     */    public void setImageAlpha(int alpha) {        mImageView.setAlpha(alpha);    }    /**     * 设置图片的大小     * 这里面需要使用LayoutParams这个布局参数来设置     *     * @param width     * @param height     */    public void setImageSize(int width, int height) {        LayoutParams layoutParams = new LayoutParams(width, height);        mImageView.setLayoutParams(layoutParams);    }    /**     * image点击事件的回调     *     * @param listener     */    public void setOnClickListener(OnItemClickListener listener) {        lis = null;        lis = listener;        mImageView.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                lis.onImageClick();            }        });    }    /**     * 点击事件接口     *     * @author linc     */    private OnItemClickListener lis;    public interface OnItemClickListener {        public void onImageClick();    }}

   
LevelMenu.java
public class LevelMenu extends LinearLayout {    private LevelMenuItem item1, item2, item3;    private String TAG = this.getClass().getName();    public LevelMenu(Context context) {        super(context);    }    public LevelMenu(Context context, AttributeSet attrs) {        super(context, attrs);        LayoutInflater layoutInflater = (LayoutInflater) context.                getSystemService(Context.LAYOUT_INFLATER_SERVICE);        layoutInflater.inflate(R.layout.level_menu, this);        initWidget();    }    public boolean setOnClickListener(int id, LevelMenuItem.OnItemClickListener lis) {        boolean bRes = false;        switch (id) {            case R.id.item1: {                item1.setOnClickListener(lis);                bRes = true;            }            break;            case R.id.item2: {                item2.setOnClickListener(lis);                bRes = true;            }            break;            case R.id.item3: {                item3.setOnClickListener(lis);                bRes = true;            }            break;        }        return bRes;    }    private void initWidget() {        item1 = (LevelMenuItem) findViewById(R.id.item1);        item2 = (LevelMenuItem) findViewById(R.id.item2);        item3 = (LevelMenuItem) findViewById(R.id.item3);    }}
layout使用 LevelMenu
<com.example.qinghua_liu.myapplication.LevelMenu    android:layout_below="@+id/item0"    android:id="@+id/levelMenu"    android:layout_width="wrap_content"    android:layout_height="wrap_content" />

自定义控件组的使用:
levelMenu = (LevelMenu) findViewById(R.id.levelMenu);levelMenu.setOnClickListener(R.id.item1, new LevelMenuItem.OnItemClickListener() {    @Override    public void onImageClick() {        Intent it = new Intent(Main2Activity.this,                ActivityMain3Activity.class);        try {            startActivity(it);        } catch (Exception e) {            Log.e(TAG, e.toString());        }        Log.e(TAG, "item1 clicked");    }});levelMenu.setOnClickListener(R.id.item2, new LevelMenuItem.OnItemClickListener() {    @Override    public void onImageClick() {        Intent it = new Intent(Main2Activity.this,                ActivityMain4Activity.class);        try {            startActivity(it);        } catch (Exception e) {            Log.e(TAG, e.toString());        }        Log.e(TAG, "item2 clicked");    }});levelMenu.setOnClickListener(R.id.item3, new LevelMenuItem.OnItemClickListener() {    @Override    public void onImageClick() {        WorkClass workClass =new WorkClass();        workClass.test();        Log.e(TAG, "item3 clicked");    }});
   
Activity Layout:
   
   


   
   


更多相关文章

  1. Android源码分析之WindowManager.LayoutParams属性更新过程
  2. Android_TextView属性XML详解
  3. 巧用Android图片资源,打造更精致的APP
  4. 图解 Android 动画中 android:pivotX 和 android:pivotY 属性的
  5. Android 实现图片保存到本地并调用本地地址显示图片
  6. Android设置拍照或者上传本地图片
  7. 简单控件的UI界面设计
  8. 第十二节(android常用控件三)
  9. ProgressBar属性小结

随机推荐

  1. Android+Jquery Mobile学习系列-目录
  2. Android(安卓)设备蓝牙连接扫描枪获取扫
  3. 前Sun开发人员为Android,iOS等其他移动平
  4. Android 上传头像(文件)到服务器
  5. android 实现QQ好友列表(扩展listview:Exp
  6. Android 广播接收者(具体例子)
  7. android 消息机制(2)
  8. Android(安卓)Toast 详解
  9. android IPC 机制
  10. Android系统下的动态Dex加载