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

来源:互联网 发布:人工智能的未来与伦理 编辑:程序博客网 时间:2024/06/05 22:30

继承自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>

第二步:在布局文件中添加CustomViewImage,注意定义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.CustomViewImageandroid: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画文字时,传入的是文字左下角的点坐标。



0 0
原创粉丝点击