自定义初学5——自定义View显示图片

前面已经简单介绍过一些自定义View的实现,现在再利用自定义View实现显示一张图片的功能

1、首先编写attrs.xml文件
<resources>

    <declare-styleable name="CustomImageView">
        <attr name="text" format="string" />
        <attr name="textSize" format="dimension" />
        <attr name="textColor" format="color" />
        <attr name="background" format="reference" />
        <attr name="imageScaleType">
            <enum name="fillXY" value="0" />
            <enum name="center" value="1" />
        </attr>
    </declare-styleable>

</resources>

2、在自定义View中获得我们自定义属性:

public class CustomImageView extends View {
    /**
     * 自定义View的宽
     */
    private int mWidth;
    /**
     * 自定义View的高
     */
    private int mHeight;
    /**
     * 自定义View的图片
     */
    private Bitmap mImage;
    /**
     * 图片的缩放模式
     */
    private int mImageScale;
    private static final int IMAGE_SCALE_FITXY = 0;
    private static final int IMAGE_SCALE_CENTER = 1;
    /**
     * 图片的标题
     */
    private String mTitle;
    /**
     * 字体的颜色
     */
    private int mTextColor;
    /**
     * 字体的大小
     */
    private int mTextSize;

    private Paint mPaint;
    /**
     * 文本的绘制范围
     */
    private Rect mTextBound;
    /**
     * 需要绘制的整个矩形范围
     */
    private Rect rect;

    public CustomImageView(Context context) {
        this(context, null);
    }
    public CustomImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }


    /**
     * 初始化自定义类型
     * 
     * @param context
     * @param attrs
     * @param defStyle
     */
    public CustomImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        TypedArray typedArray = context.getTheme().obtainStyledAttributes(
                attrs, R.styleable.CustomImageView, defStyle, 0);

        mTitle = typedArray.getString(typedArray.getIndex(0));//获得自定义属性的title
        //获得自定义属性的textSize
        mTextSize = typedArray.getDimensionPixelSize(typedArray.getIndex(1),
                (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16,
                        getResources().getDisplayMetrics()));
        //获得自定义属性的textColor
        mTextColor = typedArray.getColor(typedArray.getIndex(2), Color.BLACK);
        //获得自定义属性的image
        mImage = BitmapFactory.decodeResource(getResources(),
                typedArray.getResourceId(typedArray.getIndex(3), 0));
        //自定义属性的imageScale
        mImageScale = typedArray.getInt(typedArray.getIndex(4), 0);
        typedArray.recycle();
        rect = new Rect();
        mPaint = new Paint();
        mTextBound = new Rect();
        mPaint.setTextSize(mTextSize);
        // 计算描绘字体需要的范围
        mPaint.getTextBounds(mTitle, 0, mTitle.length(), mTextBound);

    }

3、重写onMeasure 

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        /**
         * 设置自定义View的宽度
         */
        int specMode = MeasureSpec.getMode(widthMeasureSpec);
        int specSize = MeasureSpec.getSize(widthMeasureSpec);

        if (specMode == MeasureSpec.EXACTLY)// match_parent , accurate
        {
            mWidth = specSize;
        } else {
            // 自定义View的宽度,由左右填充和图片宽度决定
            int desireByImg = getPaddingLeft() + getPaddingRight()
                    + mImage.getWidth();
            // 由左右填充和字体绘制范围的宽度决定
            int desireByTitle = getPaddingLeft() + getPaddingRight()
                    + mTextBound.width();

            if (specMode == MeasureSpec.AT_MOST)// wrap_content
            {
                int desire = Math.max(desireByImg, desireByTitle);
                mWidth = Math.min(desire, specSize);
            }
        }

        /***
         * 设置自定义View
         */

        specMode = MeasureSpec.getMode(heightMeasureSpec);
        specSize = MeasureSpec.getSize(heightMeasureSpec);
        if (specMode == MeasureSpec.EXACTLY)// 设置了明确的值或者是MATCH_PARENT
        {
            mHeight = specSize;
        } else {
            //由上下填充、图片的高度和字体绘制范围的高度决定
            int desire = getPaddingTop() + getPaddingBottom()
                    + mImage.getHeight() + mTextBound.height();
            if (specMode == MeasureSpec.AT_MOST)// wrap_content
            {
                mHeight = Math.min(desire, specSize);
            }
        }
        //为控件指定大小
        setMeasuredDimension(mWidth, mHeight);

    }

4、重写onDraw 

protected void onDraw(Canvas canvas) {
         super.onDraw(canvas);
        /**
         * 边框属性
         */
        mPaint.setStrokeWidth(4);// 设置画笔宽度
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(Color.CYAN);
        canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);

        rect.left = getPaddingLeft();
        rect.right = mWidth - getPaddingRight();
        rect.top = getPaddingTop();
        rect.bottom = mHeight - getPaddingBottom();

        mPaint.setColor(mTextColor);
        mPaint.setStyle(Style.FILL);
        /**
         * 当前设置的宽度小于字体需要的宽度,将字体改为xxx...
         */
        if (mTextBound.width() > mWidth) {
            TextPaint paint = new TextPaint(mPaint);
            String msg = TextUtils.ellipsize(mTitle, paint,
                    (float) mWidth - getPaddingLeft() - getPaddingRight(),
                    TextUtils.TruncateAt.END).toString();
            canvas.drawText(msg, getPaddingLeft(),
                    mHeight - getPaddingBottom(), mPaint);

        } else {
            // 正常情况,将字体居中
            canvas.drawText(mTitle, mWidth / 2 - mTextBound.width() * 1.0f / 2,
                    mHeight - getPaddingBottom(), mPaint);
        }

        // 取消使用掉的块
        rect.bottom -= mTextBound.height();

        if (mImageScale == IMAGE_SCALE_FITXY) {
            //绘制image
            canvas.drawBitmap(mImage, null, rect, mPaint);
        } else {
            // 计算居中的矩形范围
            rect.left = mWidth / 2 - mImage.getWidth() / 2;
            rect.right = mWidth / 2 + mImage.getWidth() / 2;
            rect.top = (mHeight - mTextBound.height()) / 2 - mImage.getHeight()
                    / 2;
            rect.bottom = (mHeight - mTextBound.height()) / 2
                    + mImage.getHeight() / 2;

            canvas.drawBitmap(mImage, null, rect, mPaint);
        }

    }

做完这些,我们就可以在activity_main.xml文件中引用了

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <com.example.activity.view.CustomImageView
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:padding="10dp"
        custom:background="@drawable/ic_launcher"
        custom:imageScaleType="center"
        custom:text="hello world !"
        custom:textColor="#00ff00"
        custom:textSize="20sp" />

    <com.example.activity.view.CustomImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:padding="10dp"
        custom:background="@drawable/ic_launcher"
        custom:imageScaleType="center"
        custom:text="hello world ! "
        custom:textColor="#ff0000"
        custom:textSize="30sp" />

    <com.example.activity.view.CustomImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:padding="10dp"
        custom:background="@drawable/wheat"
        custom:imageScaleType="fillXY"
        custom:text="麦子"
        custom:textColor="#ff0000"
        custom:textSize="12sp" />

</LinearLayout>

一共有三种效果:

  •    View宽度设置为精确值,字体的长度大于此宽度
  •    View宽度设置为wrap_content,字体的宽度大于图片
  •    View宽度设置为wrap_content, 字体的宽度小于图片

上一篇:linux 指定显示时间


下一篇:备忘:用fiddler搭一个请求响应器