Android 自定义组合控件

前言:

在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:
 
  
 
  


 
  
 
  


你可能感兴趣的:(Android)