android 开发进阶自定义控件 类似 TextView

开发自定义控件的步骤:

1. 继承View;

2.重写构造函数并构造方法中获得我们自定义的属性、

3. 重写onDraw,

4.重写onMeasure 等函数


一、自定义View的属性,首先在res/values/  下建立一个attrs.xml , 在里面定义我们的属性和声明我们的整个样式。
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="ComstomView">
         <attr name="textContent" format="string" />
        <attr name="textColor" format="color" />
        <attr name="textSize" format="dimension" />
    </declare-styleable>

</resources>



二、View类的构造方法

创建自定义控件的3种主要实现方式:
1)继承已有的控件来实现自定义控件: 主要是当要实现的控件和已有的控件在很多方面比较类似, 通过对已有控件的扩展来满足要求。
2)通过继承一个布局文件实现自定义控件,一般来说做组合控件时可以通过这个方式来实现。
    注意此时不用onDraw方法,在构造广告中通过inflater加载自定义控件的布局文件,再addView(view),自定义控件的图形界面就加载进来了。
3)通过继承view类来实现自定义控件,使用GDI绘制出组件界面,一般无法通过上述两种方式来实现时用该方式。

View(Context context)
Simple constructor to use when creating a view from code.
View(Context context, AttributeSet attrs)
Constructor that is called when inflating a view from XML.
View(Context context, AttributeSet attrs, int defStyle)
Perform inflation from XML and apply a class-specific base style.
三、自定义View增加属性的两种方法:
1)在View类中定义。通过构造函数中引入的AttributeSet 去查找XML布局的属性名称,然后找到它对应引用的资源ID去找值。
案例:实现一个带文字的图片(图片、文字是onDraw方法重绘实现)

package com.example.mycomstomview;

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.Style;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;

public class CustomView extends View {

    private Paint mPaint; // 画笔,包含了画几何图形、文本等的样式和颜色信息
    private String textContent;
    private int textColor;
    private int textSize;
    // 绘制时控制文本绘制的范围
    private Rect mBound;

    public CustomView(Context context) {
        this(context,null);

    }
    
    public CustomView(Context context, AttributeSet attrs) {
        //R.style.AppTheme,设置此处,保证layout view 的属性生效,传递到
        //CustomView(Context context, AttributeSet attrs, int defStyleAttr)
        this(context, attrs,R.style.AppTheme);
    }

    public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mPaint = new Paint();
        //mPaint.setColor(defStyleAttr);
        getConfig(context, attrs);
        mBound = new Rect();
        mPaint.getTextBounds(textContent, 0, textContent.length(), mBound);
    }
    
    private void getConfig(Context context, AttributeSet attrs) {
        // TypedArray是一个用来存放由context.obtainStyledAttributes获得的属性的数组
        TypedArray ta = context.obtainStyledAttributes(attrs,
                R.styleable.ComstomView);
        // 属性的名称是styleable中的名称+“_”+属性名称
        int n = ta.getIndexCount();
        for (int i = 0; i < n; i++) {
            int attr = ta.getIndex(i);
            switch (attr) {
            case R.styleable.ComstomView_textColor:
                textColor = ta.getColor(attr, Color.BLACK); // 提供默认值,放置未指定
                
                break;
            case R.styleable.ComstomView_textContent:
                textContent = ta.getString(attr);

                break;
            case R.styleable.ComstomView_textSize:
                // 默认设置为15sp,TypeValue也可以把sp转化为px
                textSize = ta.getDimensionPixelSize(attr,
                        (int) TypedValue.applyDimension(
                                TypedValue.COMPLEX_UNIT_SP, 15, getResources()
                                        .getDisplayMetrics()));
                mPaint.setTextSize(textSize);
                break;

            }

        }

        // 用完务必回收容器
        ta.recycle();
    }

    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        mPaint.setColor(textColor);
        canvas.drawText(textContent, getWidth() / 2 - mBound.width() / 2,
                getHeight() / 2 + mBound.height() / 2, mPaint);
    }

}

 在布局文件:中声明我们的自定义View

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:customview="http://schemas.android.com/apk/res/com.example.mycomstomview"  
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >
    
    <com.example.mycomstomview.CustomView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@android:color/holo_orange_light"
        android:padding="10dp"
        customview:textContent="我是自定义View"
        customview:textSize = "30sp"
        customview:textColor="@android:color/white"
          />

</RelativeLayout>

让我们再来看看布局xml中需要注意的事项。

首先得声明一下:xmlns:customview=http://schemas.android.com/apk/res/com.example.mycomstomview
注意,“customview”可以换成其他的任何名字,后面的url地址必须最后一部分必须用上自定义组件的包名。自定义属性了,在属性名前加上“customview”即可。


最后看一下自定义View中方法的作用:

自定义View的方法

onFinishInflate() 回调方法,当应用从XML加载该组件并用它构建界面之后调用的方法
onMeasure() 检测View组件及其子组件的大小
onLayout() 当该组件需要分配其子组件的位置、大小时
onSizeChange() 当该组件的大小被改变时
onDraw() 当组件将要绘制它的内容时
onKeyDown 当按下某个键盘时
onKeyUp  当松开某个键盘时
onTrackballEvent 当发生轨迹球事件时
onTouchEvent 当发生触屏事件时
onWindowFocusChanged(boolean)  当该组件得到、失去焦点时
onAtrrachedToWindow() 当把该组件放入到某个窗口时
onDetachedFromWindow() 当把该组件从某个窗口上分离时触发的方法
onWindowVisibilityChanged(int): 当包含该组件的窗口的可见性发生改变时触发的方法

Demo下载路径

posted @ 2015-11-25 19:05  恋恋西风  阅读(250)  评论(0编辑  收藏  举报