前面已经简单介绍过一些自定义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"
 
 
    xmlns:custom="http://schemas.android.com/apk/res/com.example.activity"
 
 
    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, 字体的宽度小于图片



效果如下:

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



源代码