Android:如何自定义View

欢迎转载,转载请注明出处:http://blog.csdn.net/aha_aha/article/details/7080320

Android下自定义控件有多种方式,如用代码实现、在xml中组合实现等。

下面介绍的是自定义View的基本方法,包括以下几个方面:

1:XML中自定义View的属性

2:在XML中自定义属性值

3:在代码中自定义View的行为

4:在XML布局文件中使用自定一个View

接下来自定义一个名为LableView的自定义View,实际上就是一个Lable,为其自定义文本、文本颜色及文本大小。

首先,在xml中自定义View的属性。新建sttrs.xml,其内容如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
     <declare-styleable name="LableView">
        <attr name="text" format="string" />
        <attr name="textColor" format="color" />
        <attr name="textSize" format="dimension" />
    </declare-styleable>
</resources>
在上面片段中,test、textcolor和textSize是自定义的属性,对于这些我们自定义的非Android标准属性,定义是需要指定他们的类型,例如上面就将text的类型指定为string。如果要使用Android标准属性,则可以这么写:

<attr name="android:text"/>

接下来定义在布局文件中要用到的颜色值。新建colors.xml,内容如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <drawable name="red">#7f00</drawable>
    <drawable name="blue">#770000ff</drawable>
    <drawable name="green">#7700ff00</drawable>
</resources>

然后定义布局文件,内容如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res/syl.test.testcustomlableview"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    
    <syl.test.testcustomlableview.LableView
            android:background="@drawable/red"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" 
            app:text="Red"/>
    
    <syl.test.testcustomlableview.LableView
            android:background="@drawable/blue"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" 
            app:text="Blue" app:textSize="20dp"/>
    
    <syl.test.testcustomlableview.LableView
            android:background="@drawable/green"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" 
            app:text="Green" app:textColor="#ffffffff" />

</LinearLayout>

上述片段中比较重要的几点:

一:首先需要在顶层xml元素中声明自己的命名空间,相应的在上述片段中为:xmlns:app="http://schemas.android.com/apk/res/syl.test.testcustomlableview"。

二:指定要使用的控件,此例中使用我们自定义的LableView控件,在上述代码片段中为syl.test.testcustomlableview。注意,之所以这么写,是因为将LableView作为一个单独的类来定义。如果将LableView作为内部类来定义,则在xml中引用时应该按如下格式来写:

<view
  class="com.android.notepad.OuterClassName$LableView"
  …… />
三:android:background="@drawable/red"引用的正是在colors.xml中定义的属性值。

四:在app:text="Red"中,app:text是在attrs.xml中自定义的属性。

LableView的源文件(LableView.java)为:

/**
 * Example of how to write a custom subclass of View. LableView
 * is used to draw simple text views. Note that it does not handle
 * styled text or right-to-left writing systems.
 *
 */
public class LableView extends View {
    private Paint mTextPaint;
    private String mText;
    private int mAscent;
    
    /**
     * Constructor.  This version is only needed if you will be instantiating
     * the object manually (not from a layout XML file).
     * @param context
     */
    public LableView(Context context) {
        super(context);
        initLableView();
    }

    /**
     * Construct object, initializing with any attributes we understand from a
     * layout file. These attributes are defined in
     * SDK/assets/res/any/classes.xml.
     * 
     * @see android.view.View#View(android.content.Context, android.util.AttributeSet)
     */
    public LableView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initLableView();

        TypedArray a = context.obtainStyledAttributes(attrs,
                R.styleable.LableView);

        CharSequence s = a.getString(R.styleable.LableView_text);
        if (s != null) {
            setText(s.toString());
        }

        // Retrieve the color(s) to be used for this view and apply them.
        // Note, if you only care about supporting a single color, that you
        // can instead call a.getColor() and pass that to setTextColor().
        setTextColor(a.getColor(R.styleable.LableView_textColor, 0xFF000000));

        int textSize = a.getDimensionPixelOffset(R.styleable.LableView_textSize, 0);
        if (textSize > 0) {
            setTextSize(textSize);
        }

        a.recycle();
    }

    private final void initLableView() {
        mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true);
        // Must manually scale the desired text size to match screen density
        mTextPaint.setTextSize(16 * getResources().getDisplayMetrics().density);
        mTextPaint.setColor(0xFF000000);
        setPadding(3, 3, 3, 3);
    }

    /**
     * Sets the text to display in this label
     * @param text The text to display. This will be drawn as one line.
     */
    public void setText(String text) {
        mText = text;
        requestLayout();
        invalidate();
    }

    /**
     * Sets the text size for this label
     * @param size Font size
     */
    public void setTextSize(int size) {
        // This text size has been pre-scaled by the getDimensionPixelOffset method
        mTextPaint.setTextSize(size);
        requestLayout();
        invalidate();
    }

    /**
     * Sets the text color for this label.
     * @param color ARGB value for the text
     */
    public void setTextColor(int color) {
        mTextPaint.setColor(color);
        invalidate();
    }

    /**
     * @see android.view.View#measure(int, int)
     */
    @Override
    protected 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 be
            result = specSize;
        } else {
            // Measure the text
            result = (int) mTextPaint.measureText(mText) + getPaddingLeft()
                    + getPaddingRight();
            if (specMode == MeasureSpec.AT_MOST) {
                // Respect AT_MOST value if that was what is called for by measureSpec
                result = 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) mTextPaint.ascent();
        if (specMode == MeasureSpec.EXACTLY) {
            // We were told how big to be
            result = specSize;
        } else {
            // Measure the text (beware: ascent is a negative number)
            result = (int) (-mAscent + mTextPaint.descent()) + getPaddingTop()
                    + getPaddingBottom();
            if (specMode == MeasureSpec.AT_MOST) {
                // Respect AT_MOST value if that was what is called for by measureSpec
                result = Math.min(result, specSize);
            }
        }
        return result;
    }

    /**
     * Render the text
     * 
     * @see android.view.View#onDraw(android.graphics.Canvas)
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawText(mText, getPaddingLeft(), getPaddingTop() - mAscent, mTextPaint);
    }
}

测试Acitivity:

public class TestCustomLableViewActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值