android自定义控件

来源:互联网 发布:蒸腾系数的算法 编辑:程序博客网 时间:2024/06/06 09:49

转载请注明出处微笑http://blog.csdn.net/u012790647



简短说说设计原由吧:

比如商品颜色属性: 可选择的有:红色,蓝色,绿色......这种一对多的关系。但是商品属性个数,每个属性里面的子性有几个都是不确定的,因此我需要动态根据其数量动态布局。控件可以不用设置id,以实现事件处理(通过回调完成)。控件可以设置自身的颜色,字体大小,字体颜色等属性。

直接先上个样本图:


该控件可以根据每个的长度自动实现换行。

代码都写了注释直接上代码:

效果一:

原始效果

package com.example.simple;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Paint.Align;import android.graphics.Paint.FontMetrics;import android.graphics.Paint.Style;import android.graphics.Path;import android.graphics.Rect;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.view.View;import com.example.androidtest_03_widght.R;/** *  * 自定义控件   */public class MyButton extends View {/** * 画笔,包含了画几何图形、文本等的样式和颜色信息 */private Paint mPaint;/** * 控件文本 */private String _text = "二零一三年";/** * 字体颜色 */private int textColor = Color.BLACK;/** * 字体大小 */private float textSize = 50;//在MEIZU MX2上必须要设置这个值才行     一般手机上只要20就够大了。。。。。/** * 存储当前按下状态 */private boolean _isPress = false;/** * 存储当前选中状态 */private boolean _isChecked = false;/** * 控件的id 该自定义控件的事件处理已经在onTouchEvent里面处理,再调用回调,可以不要id属性 */private int m_id;/** * 选中状态改变后,触发回调 */private ChangedCheckCallBack mCallback;private int _mAscent;public MyButton(Context context) {super(context);mPaint = new Paint();setPadding(10, 5, 10, 5);mPaint.setColor(textColor);mPaint.setTextSize(textSize);mPaint.setAntiAlias(true);mPaint.setDither(true);// mPaint.setTypeface(Typeface.DEFAULT_BOLD) ;//设置字体}public MyButton(Context context, AttributeSet attrs) {super(context, attrs);mPaint = new Paint();mPaint.setAntiAlias(true);// 抗锯齿mPaint.setDither(true);// 图像抖动处理setPadding(10, 5, 10, 5);// TypedArray是一个用来存放由context.obtainStyledAttributes获得的属性的数组// 在使用完成后,一定要调用recycle方法// 属性的名称是styleable中的名称+“_”+属性名称TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.MyButton);// String strText = array.getText(R.styleable.jwradiobtn_text, "");CharSequence text = array.getText(R.styleable.MyButton_android_text);if (text != null)_text = text.toString();textColor = array.getColor(R.styleable.MyButton_textColor,Color.BLACK); // 提供默认值,放置未指定textSize = array.getDimension(R.styleable.MyButton_textSize, 20);mPaint.setColor(textColor);mPaint.setTextSize(textSize);array.recycle(); // 一定要调用,否则这次的设定会对下次的使用造成影响}public void onDraw(Canvas canvas) {super.onDraw(canvas);if (_text != null && !_text.equals("")) {mPaint.setTextSize(textSize);mPaint.setColor(textColor);mPaint.setTextAlign(Align.CENTER);// 文字居中显示mPaint.setStrokeWidth(0);FontMetrics fontMetrics = mPaint.getFontMetrics();float fontHeight = fontMetrics.bottom - fontMetrics.top;// 文本高度float baseY = this.getHeight() - (this.getHeight() - fontHeight)/ 2 - fontMetrics.bottom;canvas.drawText(_text, this.getWidth() / 2, baseY, mPaint);// (this.getHeight()// -// fontHeight)/// 2// __额外// 设置了mPaint.setTextAlign(Align.CENTER);//文字居中显示// 所以canvas.drawText(text,x,y,paint);中,x,为横坐标中点位置}if (_isPress) {// 按下时边框绘制橘黄色mPaint.setColor(Color.rgb(255, 165, 0));mPaint.setStyle(Style.STROKE); // 设置填充mPaint.setStrokeWidth(5);canvas.drawRect(1, 1, this.getWidth() - 1, this.getHeight() - 1,mPaint); // 绘制矩形return;}if (_isChecked) {// 选中时边框绘制红色// Canvas中含有很多画图的接口,利用这些接口,我们可以画出我们想要的图形// mPaint = new Paint();mPaint.setColor(Color.RED);mPaint.setStyle(Style.STROKE); // 设置填充mPaint.setStrokeWidth(5);canvas.drawRect(1, 1, this.getWidth() - 1, this.getHeight() - 1,mPaint); // 绘制矩形// 绘制右下角的三角形mPaint.setStyle(Style.FILL);Path path = new Path();path.moveTo(this.getWidth(), this.getHeight());path.lineTo(this.getWidth(), this.getHeight() - 15);path.lineTo(this.getWidth() - 15, this.getHeight());canvas.drawPath(path, mPaint);} else {// 选中时边框绘制黑色mPaint.setColor(Color.BLACK);mPaint.setStyle(Style.STROKE); // 设置填充mPaint.setStrokeWidth(1);canvas.drawRect(0, 0, this.getWidth(), this.getHeight(), mPaint); // 绘制矩形}}@Overridepublic boolean dispatchTouchEvent(MotionEvent event) {// TODO Auto-generated method stub// if (event.getAction() == MotionEvent.ACTION_DOWN)// return true;return super.dispatchTouchEvent(event);}@Overridepublic boolean onTouchEvent(MotionEvent event) {// TODO Auto-generated method stubLog.e("JWRadioBtn", "JWRadioBtn_onTouchEvent:" + event.getAction());switch (event.getAction()) {case MotionEvent.ACTION_DOWN:_isPress = true;this.invalidate();// 重绘,执行onDrawreturn true;// 要返回true,后面的action_up和move才能执行case MotionEvent.ACTION_UP:if (mCallback != null) {mCallback.ChangedCheck();}_isPress = false;setChecked(!_isChecked);break;case MotionEvent.ACTION_MOVE:break;default:_isPress = false;this.invalidate();// 重绘,执行onDrawbreak;}return super.onTouchEvent(event);}/** * @see android.view.View#measure(int, int) */@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {setMeasuredDimension(measureWidth(widthMeasureSpec),measureHeight(heightMeasureSpec));}/** * Determines the width of this view *  * @param measureSpec *            A measureSpec packed into an int * @return The width of the view, honoring constraints from measureSpec */private int measureWidth(int measureSpec) {int result = 0;int specMode = MeasureSpec.getMode(measureSpec);int specSize = MeasureSpec.getSize(measureSpec);if (specMode == MeasureSpec.EXACTLY) {// We were told how big to beresult = specSize;} else {// Measure the textresult = (int) mPaint.measureText(_text) + getPaddingLeft()+ getPaddingRight();if (specMode == MeasureSpec.AT_MOST) {// Respect AT_MOST value if that was what is called for by// measureSpecresult = Math.min(result, specSize);}}return result;}/** * Determines the height of this view *  * @param measureSpec *            A measureSpec packed into an int * @return The height of the view, honoring constraints from measureSpec */private int measureHeight(int measureSpec) {int result = 0;int specMode = MeasureSpec.getMode(measureSpec);int specSize = MeasureSpec.getSize(measureSpec);_mAscent = (int) mPaint.ascent();if (specMode == MeasureSpec.EXACTLY) {// We were told how big to beresult = specSize;} else {// Measure the text (beware: ascent is a negative number)result = (int) (-_mAscent + mPaint.descent()) + getPaddingTop()+ getPaddingBottom();if (specMode == MeasureSpec.AT_MOST) {// Respect AT_MOST value if that was what is called for by// measureSpecresult = Math.min(result, specSize);}}return result;}public void setChecked(boolean value) {_isChecked = value;this.invalidate();// if (mCallback != null)// mCallback.ChangedCheck();}/** *  * @return 控件状态 true:选中 false :未被选中 */public boolean getChecked() {return _isChecked;}public void setText(String value) {_text = value;this.invalidate();}public String getText() {return _text;}public void setTextColor(int value) {textColor = value;this.invalidate();}public int getTextColor() {return textColor;}public void setTextSize(float value) {textSize = value;this.invalidate();}public float getTextSize() {return textSize;}public void setId(int id) {this.m_id = id;}public int getId() {return this.m_id;}/** * 获取控件宽度 *  * @return 文本总宽度 + padding消耗值 */public int getRealWidth() {if (this.getWidth() == 0) {Rect rect = new Rect();mPaint.getTextBounds(_text, 0, _text.length(), rect);return rect.width() + this.getPaddingLeft()+ this.getPaddingRight();} else {return this.getWidth();}}/** * 获取控件高度 *  * @return 文本高度+ pading消耗值 */public int getRealHeight() {if (this.getHeight() == 0) {Rect rect = new Rect();mPaint.getTextBounds(_text, 0, _text.length(), rect);return rect.height() + this.getPaddingTop()+ this.getPaddingBottom();} else {return this.getHeight();}}/** * 接口用于回调 */public interface ChangedCheckCallBack {void ChangedCheck();}public void setCallback(ChangedCheckCallBack callBack) {this.mCallback = callBack;}}

package com.example.simple;import java.util.ArrayList;import java.util.Arrays;import java.util.HashMap;import java.util.List;import java.util.Map;import android.app.Activity;import android.content.Context;import android.util.AttributeSet;import android.util.DisplayMetrics;import android.view.LayoutInflater;import android.widget.LinearLayout;import android.widget.TextView;import com.example.androidtest_03_widght.R;import com.example.simple.MyButton.ChangedCheckCallBack;/** * 商品属性自定义控件 * ① 可以根据项目个数动态显示 * ② 实现按钮单选 * ③ 根据最大宽度值设定自动换行 *  *  */public class AttributeMyWidget extends LinearLayout {private Context context;private LinearLayout containerLayout;private TextView attriName;private List<String> attriNameList;/** *  * 以键值对方式存放属性值, 一对多 eg:  颜色 -- 红色,绿色,蓝色,橙色   */private Map<String, List<String>> attriDetailMap;public AttributeMyWidget(Context context, AttributeSet attrs) {super(context, attrs);this.context = context;LayoutInflater.from(context).inflate(R.layout.attribute_mywidget_layout, this, true);containerLayout = (LinearLayout) this.findViewById(R.id.attri_radiogrouplayout);attriName = (TextView) this.findViewById(R.id.attriname);attriNameList = new ArrayList<String>();attriDetailMap = new HashMap<String, List<String>>();this.loadAttriData("");}/** * @param art_id *            商品id 根据id查询属性 */public void loadAttriData(String art_id) {attriNameList.add("颜色");attriNameList.add("尺码");attriDetailMap.put("颜色", Arrays.asList("红色", "深绿色", "蓝绿色", "橙色","四五个字", "五六七个字", "嘿", "很好看的颜色啊", "大大大大灰狼"));attriDetailMap.put("尺码", Arrays.asList("40", "50", "41", "42", "43"));initView("颜色");//initView("尺码");}/** * 获取屏幕的宽 *  * @param context * @return */public int getScreenWidth(Context context) {DisplayMetrics metrics = new DisplayMetrics();((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(metrics);return metrics.widthPixels;}/** * 初始化控件布局,以及数据显示 */private List<LinearLayout> radioGroupList;/** * 存放所有new出来的radioButton */private List<MyButton> radioBtnList;/** * 初始化界面 radioButton  *  * @param s */public void initView(String s) {radioBtnList = new ArrayList<MyButton>();/** * 存放randiobtn LinearLayout */LinearLayout radioLayout = null;/** * radioLayout 添加layout到radioGroup的索引号 */int index = 0;/** * 界面上最大限定宽度 如何动态获取?? */int layoutWidth = getScreenWidth(this.context);/** * layout剩余宽度 */int leftWidth = 0;/** * radionButton的宽度 */int raBtnWidth = 0;int viewNum;// 一个layout里面添加了几个radiobuttonint extraWidth; // 额外消耗的宽度值,layoutMarginradioGroupList = new ArrayList<LinearLayout>();attriName.setText(s);List<String> attriDetailList = attriDetailMap.get(s);// 所有子属性int detailNum = attriDetailList.size();// 子属性个数MyButton radioBtn;String name = "";LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);LinearLayout.LayoutParams radiobtn_params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);for (int i = 0; i < detailNum; i++) {radioBtn = new MyButton(context);name = attriDetailList.get(i);radioBtn.setText(name);raBtnWidth = radioBtn.getRealWidth();radioBtnList.add(radioBtn) ;//将radioBtn添加进list便于处理点击事件等radioBtn.setCallback(new ChangedCheckCallBack() {@Overridepublic void ChangedCheck() {//处理按下选中操作时,只能多选一int size = radioBtnList.size() ;for(int i=0;i<size ;i++){((MyButton)radioBtnList.get(i)).setChecked(false) ;}}});if (i == 0) {radioLayout = new LinearLayout(context);radioLayout.setLayoutParams(params);radioLayout.setOrientation(LinearLayout.HORIZONTAL);radioBtn.setChecked(true);// 第一个radiobutton不要左边距radiobtn_params.setMargins(0, 5, 5, 5);radioBtn.setLayoutParams(radiobtn_params);radioLayout.addView(radioBtn);containerLayout.addView(radioLayout, index);radioGroupList.add(radioLayout);// 存储radiogoupleftWidth = layoutWidth - raBtnWidth;index++;} else {radiobtn_params.setMargins(5, 5, 5, 5);radioBtn.setLayoutParams(radiobtn_params);if (raBtnWidth < leftWidth) {radioLayout.addView(radioBtn);viewNum = radioLayout.getChildCount();extraWidth = (viewNum - 1) * 10;// 额外距离消耗值leftWidth -= (raBtnWidth + extraWidth);} else {radioLayout = new LinearLayout(context);radioLayout.setLayoutParams(params);radioLayout.setOrientation(LinearLayout.HORIZONTAL);radiobtn_params.setMargins(0, 5, 5, 5);radioBtn.setLayoutParams(radiobtn_params); // 新起一行的时候第一个radiobtn不设左边距radioLayout.addView(radioBtn);//leftWidth = layoutWidth - raBtnWidth;radioGroupList.add(radioLayout);// 存储radiogoupcontainerLayout.addView(radioLayout, index);index++;}}}}}

attri,xml  这个与MyButton .java构造方法二中对应,当在xml中设置属性之后会调用该构造方法

<?xml version="1.0" encoding="utf-8" ?><resources>    <declare-styleable name="MyButton">        <attr name="android:text" />        <attr name="textColor" format="color" />        <attr name="textSize" format="dimension" />    </declare-styleable></resources>


根据上面的控件增加绘制图片,我这里改成分享按钮。当然实际中还需要添加其他处理。

效果二:

直接上代码:

package com.example.complex;import java.util.ArrayList;import java.util.Arrays;import java.util.HashMap;import java.util.List;import java.util.Map;import android.app.Activity;import android.content.Context;import android.util.AttributeSet;import android.util.DisplayMetrics;import android.util.Log;import android.view.LayoutInflater;import android.widget.LinearLayout;import android.widget.TextView;import com.example.androidtest_03_widght.R;import com.example.complex.MyButton.ChangedCheckCallBack;/** * 商品属性自定义控件 ① 可以根据项目个数动态显示 ② 实现按钮单选 ③ 根据最大宽度值设定自动换行 *  *  */public class AttributeMyWidget extends LinearLayout {private Context context;private LinearLayout containerLayout;private TextView attriName;/** *  * 以键值对方式存放属性值, 一对多 eg: 颜色 -- 红色,绿色,蓝色,橙色 */private Map<String, List<String>> attriDetailMap;/** * 位选中时,图片灰色 */private int drawble_gray[];/** * 选中时图片亮色 */private int drawble_changed[];public AttributeMyWidget(Context context, AttributeSet attrs) {super(context, attrs);this.context = context;LayoutInflater.from(context).inflate(R.layout.attribute_mywidget_layout, this, true);containerLayout = (LinearLayout) this.findViewById(R.id.attri_radiogrouplayout);attriName = (TextView) this.findViewById(R.id.attriname);attriDetailMap = new HashMap<String, List<String>>();drawble_gray = new int[] { R.drawable.logo_sml_sina_gray,R.drawable.logo_sml_tencent_gray,R.drawable.logo_sml_renren_gray };drawble_changed = new int[] { R.drawable.logo_sml_sina,R.drawable.logo_sml_tencent, R.drawable.logo_sml_renren };this.loadAttriData("a");}/** * @param art_id *            商品id 根据id查询属性 */public void loadAttriData(String art_id) {if (art_id.equals("a")) {// 里面的数组必须与图片个数相匹配attriDetailMap.put("分享",Arrays.asList(context.getResources().getStringArray(R.array.bitmaps)));attriName.setText("分享");initView("分享");} else if (art_id.equals("b")) {attriDetailMap.put("尺码",Arrays.asList("40", "50", "41", "42", "43"));initView("分享");}}/** * 获取屏幕的宽 *  * @param context * @return */public int getScreenWidth(Context context) {DisplayMetrics metrics = new DisplayMetrics();((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(metrics);return metrics.widthPixels;}/** * 初始化控件布局,以及数据显示 */private List<LinearLayout> radioGroupList;/** * 存放所有new出来的radioButton */private List<MyButton> radioBtnList;/** * 初始化界面 radioButton *  * @param s */public void initView(String s) {radioBtnList = new ArrayList<MyButton>();/** * 存放randiobtn LinearLayout */LinearLayout radioLayout = null;/** * radioLayout 添加layout到radioGroup的索引号 */int index = 0;/** * 界面上最大限定宽度 如何动态获取?? */int layoutWidth = getScreenWidth(this.context);// 根据屏幕的宽度来设置每行最大值/** * layout剩余宽度 */int leftWidth = 0;/** * radionButton的宽度 */int raBtnWidth = 0;int viewNum;// 一个layout里面添加了几个radiobuttonint extraWidth; // 额外消耗的宽度值,layoutMarginradioGroupList = new ArrayList<LinearLayout>();List<String> attriDetailList = attriDetailMap.get(s);// 所有子属性int detailNum = attriDetailList.size();// 子属性个数MyButton radioBtn;String name = "";LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);LinearLayout.LayoutParams radiobtn_params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);for (int i = 0; i < detailNum; i++) {radioBtn = new MyButton(context);name = attriDetailList.get(i);radioBtn.setBitmap(context, drawble_gray[i]);// 添加与文字对应图片显示Log.e("添加图片后的宽度:", i + " " + radioBtn.getRealWidth());radioBtn.setText(name);Log.e("添加文字后的宽度:", i + " " + radioBtn.getRealWidth());radioBtn.addBitmap_gray(drawble_gray[i]);// 添加对应灰色图片选中后的灰色图片radioBtn.addBitmap(drawble_changed[i]);// 添加对应灰色图片选中后的亮色图片raBtnWidth = radioBtn.getRealWidth();radioBtnList.add(radioBtn);// 将radioBtn添加进list便于处理点击事件等radioBtn.setCallback(new ChangedCheckCallBack() {@Overridepublic void ChangedCheck() {// 处理按下选中操作时,只能多选一int size = radioBtnList.size();for (int i = 0; i < size; i++) {((MyButton) radioBtnList.get(i)).setChecked(false);}}});if (i == 0) {radioLayout = new LinearLayout(context);radioLayout.setLayoutParams(params);radioLayout.setOrientation(LinearLayout.HORIZONTAL);radioBtn.setChecked(true);// 新起一行的时候第一个radiobutton不要左边距radiobtn_params.setMargins(0, 5, 5, 5);radioBtn.setLayoutParams(radiobtn_params);radioLayout.addView(radioBtn);containerLayout.addView(radioLayout, index);radioGroupList.add(radioLayout);// 存储radiogoupleftWidth = layoutWidth - raBtnWidth- radiobtn_params.rightMargin;index++;} else {radiobtn_params.setMargins(5, 5, 5, 5);radioBtn.setLayoutParams(radiobtn_params);if (raBtnWidth < leftWidth) {radioLayout.addView(radioBtn);viewNum = radioLayout.getChildCount();extraWidth = (viewNum - 1) * 10;// 额外距离消耗值leftWidth -= (raBtnWidth + extraWidth);} else {radioLayout = new LinearLayout(context);radioLayout.setLayoutParams(params);radioLayout.setOrientation(LinearLayout.HORIZONTAL);radiobtn_params.setMargins(0, 5, 5, 5);radioBtn.setLayoutParams(radiobtn_params); // 新起一行的时候第一个radiobtn不设左边距radioLayout.addView(radioBtn);//leftWidth = layoutWidth - raBtnWidth;radioGroupList.add(radioLayout);// 存储radiogoupcontainerLayout.addView(radioLayout, index);index++;}}}}}

package com.example.complex;import java.util.ArrayList;import java.util.List;import com.example.androidtest_03_widght.R;import com.example.androidtest_03_widght.R.styleable;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Paint.Align;import android.graphics.Paint.FontMetrics;import android.graphics.Paint.Style;import android.graphics.Path;import android.graphics.Rect;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.view.View;/** *  * 自定义控件 *  * 1. 构造方法JWRadioBtn(Context context) 动态new的时候会调用 2.JWRadioBtn(Context context, * AttributeSet attrs)控件放在xml里面设置属性时会调用 */public class MyButton extends View {/** * 画笔,包含了画几何图形、文本等的样式和颜色信息 */private Paint mPaint;/** * 控件文本 */private String _text = "二零一三年";/** * 字体颜色 */private int textColor = Color.BLACK;/** * 字体大小 */private float textSize = 50;//魅族mx2必须这个值才看得到啊    设置20小了/** * 存储当前按下状态 */private boolean _isPress = false;/** * 存储当前选中状态 */private boolean _isChecked = false;/** * 控件的id 该自定义控件的事件处理已经在onTouchEvent里面处理,再调用回调,可以不要id属性 */private int m_id;private Bitmap mBitmap;private Context context;/** * 选中状态改变后,触发回调 */private ChangedCheckCallBack mCallback;private int _mAscent;public MyButton(Context context) {super(context);this.context = context;bitmapChanged = new int[1][2];//用二为数组存放对应图片drawable int 值 [0][0] 表示灰色,[0][1]表示亮色mPaint = new Paint();setPadding(5, 10, 5, 10);mPaint.setColor(textColor);mPaint.setTextSize(textSize);mPaint.setAntiAlias(true);mPaint.setDither(true);// mPaint.setTypeface(Typeface.DEFAULT_BOLD) ;//设置字体}public MyButton(Context context, AttributeSet attrs) {super(context, attrs);this.context = context;mPaint = new Paint();mPaint.setAntiAlias(true);// 抗锯齿mPaint.setDither(true);// 图像抖动处理setPadding(5, 10, 5, 10);// TypedArray是一个用来存放由context.obtainStyledAttributes获得的属性的数组// 在使用完成后,一定要调用recycle方法// 属性的名称是styleable中的名称+“_”+属性名称TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.MyButton);// String strText = array.getText(R.styleable.jwradiobtn_text, "");CharSequence text = array.getText(R.styleable.MyButton_android_text);if (text != null)_text = text.toString();textColor = array.getColor(R.styleable.MyButton_textColor,Color.BLACK); // 提供默认值,放置未指定textSize = array.getDimension(R.styleable.MyButton_textSize, 20);mPaint.setColor(textColor);mPaint.setTextSize(textSize);array.recycle(); // 一定要调用,否则这次的设定会对下次的使用造成影响}public void onDraw(Canvas canvas) {super.onDraw(canvas);if (mBitmap != null) {canvas.drawBitmap(mBitmap, this.getPaddingLeft(),this.getPaddingTop(), mPaint);}if (_text != null && !_text.equals("")) {mPaint.setTextSize(textSize);mPaint.setColor(textColor);mPaint.setTextAlign(Align.CENTER);// 文字居中显示mPaint.setStrokeWidth(0);FontMetrics fontMetrics = mPaint.getFontMetrics();float fontHeight = fontMetrics.bottom - fontMetrics.top;// 文本高度float baseY = this.getHeight() - (this.getHeight() - fontHeight)/ 2 - fontMetrics.bottom;canvas.drawText(_text,(this.getWidth() + this.mBitmap.getWidth()) / 2, baseY,mPaint);// (this.getHeight() -fontHeight)/2__额外// 设置了mPaint.setTextAlign(Align.CENTER);//文字居中显示// 所以canvas.drawText(text,x,y,paint);中,x,为横坐标中点位置}if (_isPress) {// 按下时边框绘制橘黄色mPaint.setColor(Color.rgb(255, 165, 0));mPaint.setStyle(Style.STROKE); // 设置填充mPaint.setStrokeWidth(5);canvas.drawRect(1, 1, this.getWidth() - 1, this.getHeight() - 1,mPaint); // 绘制矩形return;}if (_isChecked) {// 选中时边框绘制红色// Canvas中含有很多画图的接口,利用这些接口,我们可以画出我们想要的图形// mPaint = new Paint();mPaint.setColor(Color.RED);mPaint.setStyle(Style.STROKE); // 设置填充mPaint.setStrokeWidth(5);canvas.drawRect(1, 1, this.getWidth() - 1, this.getHeight() - 1,mPaint); // 绘制矩形// 绘制右下角的三角形mPaint.setStyle(Style.FILL);Path path = new Path();path.moveTo(this.getWidth(), this.getHeight());path.lineTo(this.getWidth(), this.getHeight() - 15);path.lineTo(this.getWidth() - 15, this.getHeight());canvas.drawPath(path, mPaint);} else {// 边框绘制黑色mPaint.setColor(Color.BLACK);mPaint.setStyle(Style.STROKE); // 设置填充mPaint.setStrokeWidth(1);canvas.drawRect(0, 0, this.getWidth(), this.getHeight(), mPaint); // 绘制矩形}}@Overridepublic boolean dispatchTouchEvent(MotionEvent event) {// TODO Auto-generated method stub// if (event.getAction() == MotionEvent.ACTION_DOWN)// return true;return super.dispatchTouchEvent(event);}@Overridepublic boolean onTouchEvent(MotionEvent event) {// TODO Auto-generated method stubLog.e("JWRadioBtn", "JWRadioBtn_onTouchEvent:" + event.getAction());switch (event.getAction()) {case MotionEvent.ACTION_DOWN:_isPress = true;this.invalidate();// 重绘,执行onDrawreturn true;// 要返回true,后面的action_up和move才能执行case MotionEvent.ACTION_UP:if (mCallback != null) {mCallback.ChangedCheck();}_isPress = false;setChecked(!_isChecked);break;case MotionEvent.ACTION_MOVE:break;default:_isPress = false;this.invalidate();// 重绘,执行onDrawbreak;}return super.onTouchEvent(event);}/** * @see android.view.View#measure(int, int) */@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {setMeasuredDimension(measureWidth(widthMeasureSpec),measureHeight(heightMeasureSpec));}/** * Determines the width of this view *  * @param measureSpec *            A measureSpec packed into an int * @return The width of the view, honoring constraints from measureSpec */private int measureWidth(int measureSpec) {int result = 0;int specMode = MeasureSpec.getMode(measureSpec);int specSize = MeasureSpec.getSize(measureSpec);if (specMode == MeasureSpec.EXACTLY) {// We were told how big to beresult = specSize;} else {// Measure the textresult = (int) mPaint.measureText(_text) + getPaddingLeft()+ getPaddingRight() + mBitmap.getWidth();if (specMode == MeasureSpec.AT_MOST) {// Respect AT_MOST value if that was what is called for by// measureSpecresult = Math.min(result, specSize);}}return result;}/** * Determines the height of this view *  * @param measureSpec *            A measureSpec packed into an int * @return The height of the view, honoring constraints from measureSpec */private int measureHeight(int measureSpec) {int result = 0;int specMode = MeasureSpec.getMode(measureSpec);int specSize = MeasureSpec.getSize(measureSpec);_mAscent = (int) mPaint.ascent();if (specMode == MeasureSpec.EXACTLY) {// We were told how big to beresult = specSize;} else {// Measure the text (beware: ascent is a negative number)int h = (int) (-_mAscent + mPaint.descent()) + getPaddingTop()+ getPaddingBottom();if (mBitmap.getHeight() < h) {result = h;}if (specMode == MeasureSpec.AT_MOST) {// Respect AT_MOST value if that was what is called for by// measureSpecresult = Math.min(result, specSize);}}return result;}/** * 选中状态时候的图片显示 */private int[][] bitmapChanged;/** * 添加图片 亮色图片 *  * @param drawableId */public void addBitmap(Integer drawableId) {bitmapChanged[0][0] = drawableId;}/** * 添加图片 灰色图片 *  * @param drawableId */public void addBitmap_gray(Integer drawableId) {bitmapChanged[0][1] = drawableId;}public void setChecked(boolean value) {_isChecked = value;if (_isChecked) {this.setBitmap(context, bitmapChanged[0][0]);// 灰色} else {this.setBitmap(context, bitmapChanged[0][1]);// 亮色}this.invalidate();// if (mCallback != null)// mCallback.ChangedCheck();}/** *  * @return 控件状态 true:选中 false :未被选中 */public boolean getChecked() {return _isChecked;}public void setText(String value) {_text = value;this.invalidate();}public String getText() {return _text;}public void setTextColor(int value) {textColor = value;this.invalidate();}public int getTextColor() {return textColor;}public void setTextSize(float value) {textSize = value;this.invalidate();}public float getTextSize() {return textSize;}public void setId(int id) {this.m_id = id;}public int getId() {return this.m_id;}// public Bitmap getBitmap(Context context,int drawable_id){//// return BitmapFactory.decodeResource(context.getResources(), drawable_id)// ;// }public void setBitmap(Context context, int drawable_id) {this.mBitmap = BitmapFactory.decodeResource(context.getResources(),drawable_id);this.invalidate();}public Bitmap getBitmap() {return mBitmap;}/** * 获取控件宽度 *  * @return 文本总宽度 + padding消耗值 */public int getRealWidth() {if (this.getWidth() == 0) {Rect rect = new Rect();mPaint.getTextBounds(_text, 0, _text.length(), rect);Log.e("在button里rect.width()", "" + rect.width());Log.e("在button里图片的宽度", "" + mBitmap.getWidth());return rect.width() + this.getPaddingLeft()+ this.getPaddingRight() + this.mBitmap.getWidth();} else {return this.getWidth();}}/** * 获取控件高度 *  * @return 文本高度+ pading消耗值 */public int getRealHeight() {if (this.getHeight() == 0) {Rect rect = new Rect();mPaint.getTextBounds(_text, 0, _text.length(), rect);int h = rect.height() + this.getPaddingTop()+ this.getPaddingBottom();int h1 = mBitmap.getHeight();if (h < h1) {return h1;} else {return h;}} else {return this.getHeight();}}/** * 接口用于回调 */public interface ChangedCheckCallBack {void ChangedCheck();}public void setCallback(ChangedCheckCallBack callBack) {this.mCallback = callBack;}}

测试:

在华为手机和原道平板N70上面正常,但是在魅族mx2上面测试,按钮字体必须在50左右才算正常显示......


最后附上源码下载:http://download.csdn.net/detail/u012790647/6547957

原创粉丝点击