自定义View(2):自定义文本和图像显示

继承自View的文本+图像显示控件CustomViewImage,需要自定义属性:文字内容,字体颜色和字体大小;图像资源和图像显示方式。

第一步:资源文件中定义属性

<attr name="titleText" format="string" />
	<attr name="titleTextColor" format="color" />
	<attr name="titleTextSize" format="dimension" />
	<attr name="image" format="reference" />
	<attr name="imageScaleType">
		<enum name="fillXY" value="0" />
		<enum name="center" value="1" />
	</attr>

	<declare-styleable name="CustomViewImage">
		<attr name="titleText" />
		<attr name="titleTextSize" />
		<attr name="titleTextColor" />
		<attr name="image" />
		<attr name="imageScaleType" />
	</declare-styleable>

第二步:在布局文件中添加 CustomViewImag e,注意定义xmlns:custom,可以更改的是属性资源所在的包名[com.twelve],即manifest文件中定义的包名。

<?xml version="1.0" encoding="utf-8"?>

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

	<com.twelve.custom.CustomViewImage
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:layout_gravity="center"
			android:padding="10dp"
			custom:image="@drawable/girl"
			custom:imageScaleType="fillXY"
			custom:titleText="妹子~"
			custom:titleTextColor="#ff0000"
			custom:titleTextSize="12sp"/>
</LinearLayout>
第三步,获取自定义属性值

public CustomViewImage(Context context) {
        this(context, null);
    }

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

    public CustomViewImage(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        /**
         * 初始化控件边界
         */
        rect = new Rect();
        /**
         * 初始化画笔对象
         */
        mPaint = new Paint();
        /**
         * 初始化文本绘制框
         */
        mTextBound = new Rect();

        /**
         * 获取文本和图像属性
         */
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomViewImage, defStyle, 0);
        int n = a.length();
        for (int i = 0; i < n; i++) {
            int attr = a.getIndex(i);
            switch (attr) {
                case R.styleable.CustomViewImage_image:
                    /**
                     * 获取图像对象
                     */
                    mImage = BitmapFactory.decodeResource(getResources(), a.getResourceId(attr, 0));
                    break;
                case R.styleable.CustomViewImage_imageScaleType:
                    /**
                     * 获取图像显示模式
                     */
                    mImageScale = a.getInt(attr, 0);
                    break;
                case R.styleable.CustomViewImage_titleText:
                    /**
                     * 获取文本内容
                     */
                    mTitle = a.getString(attr);
                    break;
                case R.styleable.CustomViewImage_titleTextColor:
                    /**
                     * 获取文本颜色
                     */
                    mTextColor = a.getColor(attr, Color.BLACK);
                    break;
                case R.styleable.CustomViewImage_titleTextSize:
                    /**
                     * 获取文本字号
                     */
                    mTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
                            16, getResources().getDisplayMetrics()));
                    mPaint.setTextSize(mTextSize);
                    break;
            }
        }
        a.recycle();
        /**
         * 获取文本占据上控件画布的大小
         */
        mPaint.getTextBounds(mTitle, 0, mTitle.length(), mTextBound);
    }


【下面两步,就是《自定义View(1)中“ 这里就引入了两个最重要的重载方法:onMeasure/onDraw”》】
第四步:确定控件的宽度和高度

/**
     * 确定视图的总宽度和总高度
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        /**
         * 设置宽度
         */
        if (widthMode == MeasureSpec.EXACTLY){
            /**
             * 如果显示模式为指定大小,宽度就是给定的宽度
             */
            mWidth = widthSize;
        } else {
            /**
             * 由图片决定的宽度:图片本身的宽度+与边界的距离
             */
            int desireByImg = getPaddingLeft() + getPaddingRight() + mImage.getWidth();
            /**
             * 由文字决定的宽度:文字本身的宽度+与边界的距离
             */
            int desireByTitle = getPaddingLeft() + getPaddingRight() + mTextBound.width();

            /**
             * 可变宽度下,原则上使得内容显示不超出边界。
             */
            int desire = Math.max(desireByImg, desireByTitle);
            mWidth = Math.min(desire, widthSize);
        }
        /**
         * 设置高度
         */
        if (heightMode == MeasureSpec.EXACTLY){
            /**
             * 如果显示模式为指定大小,高度就是给定的高度
             */
            mHeight = heightSize;
        } else {
            /**
             * 由图片和文字决定的高度:图片本身的高度+文字本身高度+与边界的距离
             */
            int desire = getPaddingTop() + getPaddingBottom() + mImage.getHeight() + mTextBound.height();
            /**
             * 可变高度下,原则上使得内容显示不超出边界。
             */
            mHeight = Math.min(desire, heightSize);
        }
        setMeasuredDimension(mWidth, mHeight);
    }
第五步,按照上面图像下面文字的方式,把文字和图像显示显示到屏幕上。

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        mPaint.setStrokeWidth(4);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(Color.BLUE);
        /**
         * 边框:View视图最外边框,与内容距离--padding
         */
        canvas.drawRect(0,0,getWidth(),getHeight(), mPaint);

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

        /**
         * 边框:紧贴着文字和图像内容的长方形边框
         */
        mPaint.setColor(Color.RED);
        canvas.drawRect(rect, mPaint);

        mPaint.setColor(mTextColor);
        mPaint.setStyle(Paint.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_FIT_XY) {
            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);
        }
    }
canvas画方框时传入的是方框对象;canvas画图片时,传入方框是图像的边界,图像会被画在方框内;canvas画文字时,传入的是文字左下角的点坐标。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值