自定义图文并茂的Button

来源:互联网 发布:python telnet expect 编辑:程序博客网 时间:2024/06/06 08:57
anroid内置了Button和ImageButton,但是没有提供既能显示图片又能显示文字的button。
这里我自定义了一个ImageTextButton
其中了XML文件中使用了自定义属性custom:icon="@drawable/icon"
下面是ImageTextButton源码:
import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.util.AttributeSet;import android.widget.Button;public class ImageTextButton extends Button {private final String namespace =  "http://www.iteye.com/custom";private int resourceId =0;private Bitmap bitmap;public ImageTextButton(Context context, AttributeSet attrs) {super(context, attrs);// TODO Auto-generated constructor stubsetClickable(true);//默认使用R.drawable.icon这张图片resourceId = attrs.getAttributeResourceValue(namespace, "icon", R.drawable.icon);bitmap = BitmapFactory.decodeResource(getResources(), resourceId);}@Overrideprotected void onDraw(Canvas canvas) {// TODO Auto-generated method stub//图片顶部居中显示int x=(this.getMeasuredWidth()-bitmap.getWidth())>>1;int y=0;        canvas.drawBitmap(bitmap, x, y, null);         //坐标需要转换,因为默认情况下Button中的文字居中显示        //这里需要让文字在底部显示canvas.translate(0, (this.getMeasuredHeight()>>1)-(int)this.getTextSize());super.onDraw(canvas);}    public void setIcon(Bitmap bitmap){this.bitmap=bitmap;                invalidate();}    public void setIcon(int resourceId){this.bitmap=BitmapFactory.decodeResource(getResources(), resourceId);                invalidate();}}


<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:custom="http://www.iteye.com/custom"    android:orientation="vertical"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    >    <com.wt.app.ImageTextButton     android:text="OK"    custom:icon="@drawable/icon"    android:id="@+id/button_0" android:layout_width="80dip" android:layout_height="80dip"    />    <com.wt.app.ImageTextButton     android:text="OK"    custom:icon="@drawable/icon"    android:id="@+id/button_1" android:layout_width="80dip" android:layout_height="100dip"android:textSize="30dip"android:textColor="#ff0000"    />        <com.wt.app.ImageTextButton     android:text="OK"    custom:icon="@drawable/icon"    android:id="@+id/button_2" android:layout_width="200dip" android:layout_height="200dip"android:textSize="30dip"    />   </LinearLayout>




另一种实现:
import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Rect;import android.view.MotionEvent;import android.view.View; public class ImageTextButton extends View{ private final static int WIDTH_PADDING = 8;private final static int HEIGHT_PADDING = 10;private final static int SPACE = 10;private final String label;private final int imageResId;private final Bitmap image;private int fontWidth;private int fontHeight; public ImageTextButton(final Context c,int rid,String text){super(c);this.label = text;this.imageResId = rid;this.image = BitmapFactory.decodeResource(c.getResources(),imageResId);setFocusable(true);setClickable(true);getFontWidthAndHeight();} private void getFontWidthAndHeight(){Paint pFont = new Paint(); Rect rect = new Rect(); pFont.getTextBounds("信 ", 0, 1, rect); this.fontHeight = rect.height();this.fontWidth = rect.width();} private int getTextWidth(String text){return text.length()*this.fontWidth;} @Overrideprotected void onFocusChanged(boolean gainFocus, int direction,Rect previouslyFocusedRect) {if (gainFocus == true){this.setBackgroundColor(Color.rgb(255, 165, 0));}else{this.setBackgroundColor(Color.alpha(0));}} @Overrideprotected void onDraw(Canvas canvas) {Paint textPaint = new Paint();textPaint.setColor(Color.WHITE);canvas.drawBitmap(image, WIDTH_PADDING / 2, HEIGHT_PADDING / 2, null);canvas.drawText(label, (image.getWidth()-getTextWidth(label)/2)/ 2, (HEIGHT_PADDING / 2) +image.getHeight() + 8+SPACE, textPaint);} @Overridepublic boolean onTouchEvent(MotionEvent event) {int action = event.getAction();switch(action){case MotionEvent.ACTION_DOWN:case MotionEvent.ACTION_MOVE:this.setBackgroundColor(Color.rgb(255, 165, 0));break;case MotionEvent.ACTION_UP:case MotionEvent.ACTION_CANCEL:this.setBackgroundColor(Color.alpha(0));break;} return super.onTouchEvent(event);} @Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {setMeasuredDimension(measureWidth(widthMeasureSpec),measureHeight(heightMeasureSpec));} private int measureWidth(int measureSpec){int preferred = image.getWidth() * 2;return getMeasurement(measureSpec, preferred);}private int measureHeight(int measureSpec){   int preferred = image.getHeight()+this.fontHeight+SPACE*2;   return getMeasurement(measureSpec, preferred);} private int getMeasurement(int measureSpec, int preferred){  int specSize = MeasureSpec.getSize(measureSpec);int measurement = 0;switch(MeasureSpec.getMode(measureSpec)){case MeasureSpec.EXACTLY:measurement = specSize;break;case MeasureSpec.AT_MOST:measurement = Math.min(preferred, specSize);break;default:measurement = preferred;break;}return measurement;} public String getLabel(){return label;}   public int getImageResId(){return imageResId;} }


说说Android 两种为自定义组件添加属性的使用方法和区别
http://terryblog.blog.51cto.com/1764499/414884

Android高手进阶教程(四)之----Android 中自定义属性(attr.xml,TypedArray)的使用!
http://blog.csdn.net/Android_Tutor/archive/2010/04/20/5508615.aspx

linearlayout继承扩展篇
http://wang-peng1.iteye.com/blog/576151

另一篇:编写Android自定义按钮
http://marshal.easymorse.com/archives/3059


实现按钮,这里没有通过Button类或者子类去做派生,而是通过TextView派生出来的。在这里三个按钮是三个TextView派生类实例,中间的白线,是1px宽的白色矩形,这样就可以做出类似上面的效果。
看布局文件:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     android:orientation="vertical" android:layout_width="fill_parent"    android:layout_height="fill_parent" android:background="@drawable/background_color">     <LinearLayout android:layout_width="fill_parent"         android:layout_height="10dip" />     <LinearLayout android:layout_width="fill_parent"         android:layout_height="40dip">         <com.easymorse.textbutton.TextButton             android:layout_width="fill_parent" android:layout_height="fill_parent"             android:layout_weight="1" android:text="电影"             android:gravity="center_vertical|center_horizontal"             android:background="@drawable/button" android:focusable="true" android:clickable="true"/>         <View android:layout_width="2px" android:layout_height="fill_parent"             android:background="#ffffffff" />         <com.easymorse.textbutton.TextButton             android:layout_width="fill_parent" android:layout_height="fill_parent" android:clickable="true"             android:layout_weight="1" android:text="电视"             android:gravity="center_vertical|center_horizontal"             android:background="@drawable/button" android:focusable="true" />         <View android:layout_width="2px" android:layout_height="fill_parent"             android:background="#ffffffff" />         <com.easymorse.textbutton.TextButton             android:layout_width="fill_parent" android:layout_height="fill_parent" android:clickable="true"             android:layout_weight="1" android:text="明星"             android:gravity="center_vertical|center_horizontal"             android:background="@drawable/button" android:focusable="true" />     </LinearLayout> </LinearLayout>

这里需要注意的几点:

对于布局的像素设置,一般要用dip,这样在更大或者更小的屏幕下展示可以自动适配,如果是px,是物理像素,这样在小的屏幕里面可能会显得大,在大的屏幕中显得小
在按钮布局中要使用android:focusable="true" android:clickable="true",这样才能比如通过轨迹球聚焦到按钮上,才能用手触摸按钮的时候触发事件
点击按钮变色,主要在android:background="@drawable/button"配置,button配置了点击事件发生后的背景色改变,而不需要编写代码
下面来看看drawable/button.xml文件:
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"     android:constantSize="true">     <item android:state_focused="true">         <shape>             <gradient android:startColor="#FFE5CF33" android:endColor="#FFF1E7A2"                 android:angle="90.0">             </gradient>         </shape>     </item>     <item android:state_enabled="true" android:state_pressed="false">         <shape>             <gradient android:startColor="#FF1B1B1B" android:endColor="#FF969696"                 android:angle="90.0">             </gradient>         </shape>     </item>     <item android:state_enabled="true" android:state_pressed="true">         <shape>             <gradient android:startColor="#FF000000" android:endColor="#FF474747"                 android:angle="90.0">             </gradient>         </shape>     </item>     <item android:state_enabled="false" android:state_pressed="true">         <shape>             <gradient android:startColor="#FF000000" android:endColor="#FF474747"                 android:angle="90.0">             </gradient>         </shape>     </item>     <item>         <shape>             <gradient android:startColor="#FF000000" android:endColor="#FF474747"                 android:angle="90.0">             </gradient>         </shape>     </item> </selector>

这个文件中定义了当条目(也就是按钮)enable和(或)pressed的情况下的背景渐近色的配置情况。

实际上,上面介绍的部分,在不使用自定义按钮(也就是不是<com.easymorse.textbutton.TextButton而直接写<TextView…)的情况下,已经可以出现除了点击后Toast消息。
说一下TextView的派生类,其实只是在touche按钮的时候显示提示信息:
import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.widget.TextView; import android.widget.Toast;public class TextButton extends TextView {    public TextButton(Context context) {         super(context);     }    public TextButton(Context context, AttributeSet attrs, int defStyle) {         super(context, attrs, defStyle);     }    public TextButton(final Context context, AttributeSet attrs) {         this(context, attrs, 0);        this.setOnTouchListener(new OnTouchListener() {            @Override             public boolean onTouch(View v, MotionEvent event) {                 if (event.getAction() == MotionEvent.ACTION_CANCEL                         || event.getAction() == MotionEvent.ACTION_UP                         || event.getAction() == MotionEvent.ACTION_OUTSIDE) {                     Toast.makeText(context, "touched", Toast.LENGTH_SHORT).show();                 }                 return false;             }         });     }}

在这里主要是写了设置OnTouchListener的代码。

这里只针对3种情况才显示提示:

当手指从按钮抬起,ACTION_UP
取消,ACTION_CANCEL
手指移出按钮,ACTION_OUTSIDE
另外,要返回false,因为返回true,系统将不会调用drawable/button.xml的效果,因为true表示自己已经处理了onTouche事件,不需要别的逻辑再处理了。
源代码见:http://easymorse.googlecode.com/svn/tags/textButton-0.1.0/

用自定义Button实现ToggleButton
http://marshal.easymorse.com/archives/3045

附送:自定义的竖着的seekbar(转)
原创粉丝点击