新书内容连载(1):自定义Android组件之带图像的TextView

本文为原创,如需转载,请注明作者和出处,谢谢!

本文为新书《Android/OPhone 开发完全讲义》的内容连载。《Android/OPhone开发完全讲义》一书现已出版,敬请关注。

购 买: 互动网

《Android/OPhone 开发完全讲义》目录

源代码下载

新书内容连载(1):自定义Android组件之带图像的TextView


    在本例中要实现一个可以在文本前方添加一个 图像(可以是任何Android系统支持的图像格式)的TextView组件。在编写代码之前,先看一下Android组件的配置代码。

< TextView  android:id ="@+id/textview1"  android:layout_width ="fill_parent"
        android:layout_height
="wrap_content"  android:text ="textview1"  />

     在构造方法中可以通过AttributeSet接口的相应getter方法来读取指定的属性值,如果 在配置属性时指定了命名空间,需要在使用getter方法获得属性值时指定这个命名空间,如果未指定命名空间,则将命名空间设为null即可。

    IconTextView是本例要编写的组件类,该类从TextView继承,在onDraw方法中将TextView中的文本后移,并在文本的前方添加了一个图像,该图像的资源ID通过mobile:iconSrc属性来指定。IconTextView类的代码如下:

package  net.blogjava.mobile.widget;

import  android.content.Context;
import  android.graphics.Bitmap;
import  android.graphics.BitmapFactory;
import  android.graphics.Canvas;
import  android.graphics.Rect;
import  android.util.AttributeSet;
import  android.widget.TextView;

public  class  IconTextView  extends  TextView
{
    
//   命名空间的值
     private  final  String namespace  =  " http://net.blogjava.mobile " ;
    
//   保存图像资源ID的变量
     private  int  resourceId  =  0 ;
    
private  Bitmap bitmap;
    
public  IconTextView(Context context, AttributeSet attrs)
    {
        
super (context, attrs);
        
//   getAttributeResourceValue方法用来获得组件属性的值,在 本例中需要通过该方法的第1个参数指
         
//   定命名空间的值。该方法的第2个参数表示组件属性名(不包括命名空间名称),第3个 参数表示默
         
//   认值,也就是如果该属性不存在,则返回第3个参数指定的值
        resourceId  =  attrs.getAttributeResourceValue(namespace,  " iconSrc " 0 );
        
if  (resourceId  >  0 )
              
//   如果成功获得图像资源的ID,装载这个图像资源,并创建Bitmap对象
            bitmap  =  BitmapFactory.decodeResource(getResources(), resourceId);
    }
    @Override
    
protected  void  onDraw(Canvas canvas)
    {
        
if  (bitmap  !=  null )
        {
            
//   从原图上截取图像的区域,在本例中为整个图像
            Rect src  =  new  Rect();
            
//   将截取的图像复制到bitmap上的目标区域,在本例中与复制区域相同
            Rect target  =  new  Rect();
            src.left 
=  0 ;
            src.top 
=  0 ;
            src.right 
=  bitmap.getWidth();
            src.bottom 
=  bitmap.getHeight();
            
int  textHeight  =  ( int ) getTextSize();
            target.left 
=  0 ;
            
//   计算图像复制到目标区域的纵坐标。由于TextView组件的文本内容并不是
              
//   从最顶端开始绘制的,因此,需要重新计算绘制图像的纵坐标
            target.top  =  ( int ) ((getMeasuredHeight()  -  getTextSize())  /  2 +  1 ;
            target.bottom 
=  target.top  +  textHeight;
            
//   为了保证图像不变形,需要根据图像高度重新计算图像的宽度
            target.right  =  ( int ) (textHeight  *  (bitmap.getWidth()  /  ( float ) bitmap.getHeight()));
            
//   开始绘制图像
            canvas.drawBitmap(bitmap, src, target, getPaint());
            
//   将TextView中的文本向右移动一定的距离(在本例中移动了图像宽度加2个象素 点的位置)
            canvas.translate(target.right  +  2 0 );
        }
        
super .onDraw(canvas);
    }
}

 

在编写上面代码时需要注意如下3点:
1.  需要指定命名空间的值。该值将在<LinearLayout>标签的xmlns:mobile属性中定义。
2.  如果在配置组件的属性时指定了命名空间,需要在AttributeSet 接口的相应getter方法中的第1个参数指定命名空间的值,而第2个参数只需指定不带命名空间的属性名即可。
3.  TextView类中的onDraw方法一定要在translate方法后面执行,否则系统不会移动TextView中的文本。

运行本实例后,将显示如图1 所示的效果。
新书内容连载(1):自定义Android组件之带图像的TextView

    注意:虽然很多人认为组件的属性必须以android命名空间开头,该命名空间的值必须是http://schemas.android.com/apk/res/android。实际上,只是命名空间的值必须是http://schemas.android.com/apk/res/android而已,命名空间的名称可以是任何值,如下面的代码所示:

<? xml version="1.0" encoding="utf-8" ?>
<!--   将android换成了abcd   -->
< LinearLayout  xmlns:abcd ="http://schemas.android.com/apk/res/android"
    abcd:orientation
="vertical"  abcd:layout_width ="fill_parent"
    abcd:layout_height
="fill_parent" >
     
</ LinearLayout >

 
下一篇:新书内容连载(2):Android Activity的生命周期

你可能感兴趣的:(textview)