像系统自带控件的一样,做一个真正的控件。
第一步:定义一个有图片和文本的布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<ImageView
android:id="@+id/widget_image_text_btn_Img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextView
android:id="@+id/widget_image_text_btn_TV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000000"
android:layout_marginLeft="8dip"
android:layout_gravity="center_vertical"
/>
</LinearLayout>
第二步:定义一个与这个布局对应的类:
package com.widget;
import com.example.testdrawable.R;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
public class ImgTextBtnH extends LinearLayout {
private static final String TAG = ImgTextBtnH.class.getSimpleName();
private ImageView mImg;
private TextView mTV;
private Button mBtn;
private Context mContext = null;
public ImgTextBtnH(Context context) {
this(context, null);
mContext = context;
}
protected void inflaterLayout(Context context) {
// 导入布局
LayoutInflater.from(context).inflate(R.layout.widget_image_text_btn_horizontal_layout, this, true);
}
@SuppressLint("NewApi")
public ImgTextBtnH(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
Resources.Theme theme = context.getTheme();
inflaterLayout(context);
// 导入布局
// LayoutInflater.from(context).inflate(R.layout.widget_image_text_btn_layout, this, true);
mImg = (ImageView) findViewById(R.id.widget_image_text_btn_Img);
mTV = (TextView) findViewById(R.id.widget_image_text_btn_TV);
mBtn = (Button) findViewById(R.id.widget_image_text_btn_Btn);
//不能够使用ImageView的click方法, 在android里点击事件消息是从内向外传递的,设置了false之后才能传递出来给LinearLayout
mImg.setClickable(false); //谢谢 Brightshadow11111 朋友的提醒
TypedArray typeArray = context.obtainStyledAttributes(attrs,
R.styleable.ImgTextBtn);
if (typeArray == null) {
return;
}
int count = typeArray.getIndexCount();
int resId = 0;
for (int i = 0; i < count; i++) {
int attr = typeArray.getIndex(i);
switch(attr) {
case R.styleable.ImgTextBtn_ImgDraw:
Drawable background = typeArray.getDrawable(attr);
int sdk = android.os.Build.VERSION.SDK_INT;
if(sdk < android.os.Build.VERSION_CODES.JELLY_BEAN) {
mImg.setBackgroundDrawable(background);
} else {
mImg.setBackground(background);
}
break;
case R.styleable.ImgTextBtn_ImgDrawWidth:
int imageWidth = typeArray.getDimensionPixelSize(attr, -1);
mImg.setMaxWidth(imageWidth);
mImg.setMinimumWidth(imageWidth);
break;
case R.styleable.ImgTextBtn_ImgDrawHeight:
int imageHeight = typeArray.getDimensionPixelSize(attr, -1);
mImg.setMaxHeight(imageHeight);
mImg.setMinimumHeight(imageHeight);
break;
case R.styleable.ImgTextBtn_ImgDrawMinWidth:
int imageMinWidth = typeArray.getDimensionPixelSize(attr, -1);
mImg.setMinimumHeight(imageMinWidth);
break;
case R.styleable.ImgTextBtn_ImgDrawMinHeight:
int imageMinHeight = typeArray.getDimensionPixelSize(attr, -1);
mImg.setMinimumHeight(imageMinHeight);
break;
case R.styleable.ImgTextBtn_ImgDrawMaxHeight:
int imageMaxHeight = typeArray.getDimensionPixelSize(attr, -1);
mImg.setMaxHeight(imageMaxHeight);
break;
case R.styleable.ImgTextBtn_ImgDrawMaxWidth:
int imageMaxWidth = typeArray.getDimensionPixelSize(attr, -1);
mImg.setMaxWidth(imageMaxWidth);
break;
case R.styleable.ImgTextBtn_TVText:
mTV.setText(typeArray.getText(attr));
break;
case R.styleable.ImgTextBtn_TVTextSize:
mTV.setTextSize(typeArray.getDimensionPixelSize(attr, 15));
break;
}
}
typeArray.recycle();
}
@Override
public void refreshDrawableState() {
// TODO Auto-generated method stub
super.refreshDrawableState();
//------------接下来处理联动效果,关键代码,请认真看-------------------
//------------ ImageView控件的联动刷新 -------------------
Drawable imgDrawable = mImg.getBackground(); //获取drawable资源
Log.d(TAG, "drawable = " + imgDrawable);
if (imgDrawable != null && imgDrawable.isStateful()) {
//关键中的关键,根据当前状态设置drawable的状态,本来应该是LinearLayout的getDrawableState()状态,
//但是现在是实现联动效果,而且获取的ImageView的getDrawState()结果不对。
imgDrawable.setState(this.getDrawableState());
}
//------------- TextView的联动刷新, 抱歉, 无法刷新 ------------------
//这块代码很快写出来了,但是写出来后发现,颜色总是停留在最后一次的颜色上,后面再点击都无法改变颜色了,
//才恍然大悟,mTV.setTextColor()是设置TextView内部的ColorStateList对象的,这样会清掉原先的
//res/color/colorSelector.xml里的设置,导致只有一种颜色值。应该赋值给TextView内部的private int mCurTextColor;
//可惜没有并设置mCurTextColor值的接口,不知到使用反射能否做到,有兴趣朋友可以一试。
//既然Text的color是靠TextPaint刷出来的,那么是否可以改变TextPaint的颜色值呢?发现有接口getPaint可以获取到TextPaint,
//但是设置了color值之后,还是不行,哦,原来在onDraw()函数中,重新设置了颜色值,所以白设了。
//总而言之,联动刷新颜色是不行滴,只能设一个颜色(对于我目前来讲功能已经是足够了) 哈哈,讲的够详细吧~~
ColorStateList mTextColor = mTV.getTextColors();
int color = mTextColor.getColorForState(this.getDrawableState(), 0);
if (mTV.getCurrentTextColor() != color) {
mTV.getPaint().setColor(color);
// mTV.setTextColor(color);
mTV.invalidate();
}
//-----------如果有个Button的话就可以在这里设置改变,效果同上,略---------------
// Drawable btnDrawable = mBtn.getBackground();
// Log.d(TAG, "drawable = " + btnDrawable);
// if (btnDrawable != null && btnDrawable.isStateful()) {
// btnDrawable.setState(this.getDrawableState());
// }
//
// ColorStateList mTextColor2 = mBtn.getTextColors();
// int color2 = mTextColor2.getColorForState(this.getDrawableState(), 0);
// if (mBtn.getCurrentTextColor() != color2) {
// mBtn.setTextColor(color2);
// }
}
/**
* 设置图片资源
*/
public void setImgViewResource(int resId) {
mImg.setImageResource(resId);
}
/**
* 设置图片
*/
public void setImgViewResource(Bitmap bitmap) {
mImg.setImageBitmap(bitmap);
}
/**
* 设置显示的文字
*/
public void setTextViewText(int resId) {
mTV.setText(resId);
}
/**
* 设置显示的文字
*/
public void setTextViewText(String text) {
mTV.setText(text);
}
}
第三步:
在value/下面定义一个attrs.xml文件,内容如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ImgTextBtn">
<attr name="ImgDraw" format="reference"></attr>
<attr name="ImgDrawWidth" format="dimension"></attr>
<attr name="ImgDrawHeight" format="dimension"></attr>
<attr name="ImgDrawMinWidth" format="dimension"></attr>
<attr name="ImgDrawMinHeight" format="dimension"></attr>
<attr name="ImgDrawMaxWidth" format="dimension"></attr>
<attr name="ImgDrawMaxHeight" format="dimension"></attr>
<attr name="TVText" format="reference|string"></attr>
<attr name="TVTextSize" format="dimension"></attr>
<attr name="TVTextColor" format="reference|color"></attr>
</declare-styleable>
</resources>
第四步:
直接在布局中使用
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:CustomAttrs="http://schemas.android.com/apk/res/com.example.testdrawable"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.widget.ImgTextBtn
android:id="@+id/imageTextButton1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_above="@+id/textView1"
android:layout_centerHorizontal="true"
android:layout_marginBottom="35dp"
android:background="@drawable/preference_round_rect_light_blue"
CustomAttrs:TVText="@string/hello_world"
CustomAttrs:TVTextSize="@dimen/dimens_Padding_normal"
CustomAttrs:ImgDraw="@drawable/test_btn_selector">
</com.widget.ImgTextBtn>
</RelativeLayout>
第五步:
代码中设置:
ImgTextBtn mBtn = (ImgTextBtn) findViewById(R.id.imageTextButton1);
mbtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Toast.makeText(MainActivity.this, "OK OK OK", Toast.LENGTH_LONG).show();
}
});
运行效果如下: