Android 自定义控件进阶:图文混排

2017/01/01 23:58
阅读数 1.2K

转载至:http://blog.csdn.net/lmj623565791/article/details/24300125

首先我们来看一下要达到的效果:


继续自定义View之旅,前面已经介绍过一个自定义View的基础的例子,Android 自定义控件起步:自定义TextView,如果你还对自定义View不了解可以去看看。今天给大家带来一个稍微复杂点的例子。
自定义View显示一张图片,下面包含图片的文本介绍,类似相片介绍什么的,不过不重要,主要是学习自定义View的用法么。
还记得上一篇讲的4个步骤么:

  • 1、自定义View的属性
  • 2、在View的构造方法中获得我们自定义的属性
  • [ 3、重写onMesure ]
  • 4、重写onDraw

直接切入正题:

1、在res/values/attr.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--CustomImageView  1、自定义View的属性 -->
    <attr name="imageTitleText" format="string" />
    <attr name="imageTitleTextColor" format="color" />
    <attr name="imageTitleTextSize" format="dimension" />
    <attr name="image" format="reference" /><!--注意image的格式-->
    <attr name="imageScaleType">
        <enum name="fillXY" value="0" />
        <enum name="center" value="1" />
    </attr>
    <declare-styleable name="CustomImageView">
        <attr name="imageTitleText" />
        <attr name="imageTitleTextColor" />
        <attr name="imageTitleTextSize" />
        <attr name="image" />
        <attr name="imageScaleType" />
    </declare-styleable>
</resources>

2、在构造中获得我们的自定义属性:

    /** * 初始化所特有自定义类型 */
    public CustomImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomImageView, defStyleAttr, 0);
        int indexCount = a.getIndexCount();
        for (int i = 0; i < indexCount; i++) {
            int arr = a.getIndex(i);
            switch (arr) {
                case R.styleable.CustomImageView_image:// 得到设置的图片
                    mImage = BitmapFactory.decodeResource(getResources(), a.getResourceId(arr, 0));
                    break;
                case R.styleable.CustomImageView_imageScaleType:// 图片显示形式
                    mImageScaleType = a.getInt(a.getIndex(arr), 0);
                    break;
                case R.styleable.CustomImageView_imageTitleText:// 文字
                    mTitleText = a.getString(arr);
                    break;
                case R.styleable.CustomImageView_imageTitleTextColor:// 文字颜色
                    mTitleTextColor = a.getColor(a.getIndex(arr), 0);
                    break;
                case R.styleable.CustomImageView_imageTitleTextSize:// 文字字号
                    mTitleTextSize = a.getDimensionPixelSize(arr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
                    break;
            }
        }
        a.recycle();

        mRect = new Rect();
        mPaint = new Paint();
        mTextBound = new Rect();
        mPaint.setTextSize(mTitleTextSize);
        // 计算了描绘字体需要的范围
        if (!TextUtils.isEmpty(mTitleText)) {
            mPaint.getTextBounds(mTitleText, 0, mTitleText.length(), mTextBound);
        }
    }

3、重写onMeasure

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        /** * 设置宽度 */
        int specMode = MeasureSpec.getMode(widthMeasureSpec);
        int specSize = MeasureSpec.getSize(widthMeasureSpec);
        if (specMode == MeasureSpec.EXACTLY) {
            mWidth = specSize;
        } else {
            // 图片宽
            int mImageWidth = getPaddingLeft() + getPaddingRight() + mImage.getWidth();//图片宽:直接getWidth();
            // 文字宽
            int mTextWidth = getPaddingLeft() + getPaddingRight() + mTextBound.width();
            if (specMode == MeasureSpec.AT_MOST) {
                int des = Math.max(mImageWidth, mTextWidth);
                // 有可能的情况是占满全屏,为保险去最小的
                mWidth = Math.min(des, specSize);
            }
        }
        /** * 设置高度 */
        specMode = MeasureSpec.getMode(heightMeasureSpec);
        specSize = MeasureSpec.getSize(heightMeasureSpec);
        if (specMode == MeasureSpec.EXACTLY) {
            mHeight = specSize;
        } else {
            int des = getPaddingTop() + getPaddingBottom() + mImage.getHeight() + mTextBound.height();
            // 有可能是全屏的,取最小的高度
            if (specMode == MeasureSpec.AT_MOST) {
                mHeight = Math.min(des, specSize);
            }
        }
        setMeasuredDimension(mWidth, mHeight);
    }

4、重写onDraw

@Override
    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);

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

        mPaint.setColor(mTitleTextColor);
        mPaint.setStyle(Paint.Style.FILL);

        /** * 当前设置的宽度小于字体的需要的宽度,将字体改为xxx... */
        if (mTextBound.width() > mWidth) {
            TextPaint paint = new TextPaint(mPaint);
            String msg = TextUtils.ellipsize(mTitleText, paint, (float) mWidth - getPaddingLeft() - getPaddingRight(), TextUtils.TruncateAt.END).toString();
            canvas.drawText(msg, getPaddingLeft(), mHeight - getPaddingBottom(), mPaint);
        } else {
            // 正常情况下将字体居中
            canvas.drawText(mTitleText, mWidth / 2 - mTextBound.width() / 2, mHeight - getPaddingBottom(), mPaint);
        }
        // 取消使用掉的块(图片)
        mRect.bottom -= mTextBound.height();
        if (mImageScaleType == IMAGE_SCALE_FITXY) {
            canvas.drawBitmap(mImage, null, mRect, mPaint);
        } else { //居中
            // 计算居中的矩形范围
            mRect.left = mWidth / 2 - mImage.getWidth() / 2;
            mRect.right = mWidth / 2 + mImage.getWidth() / 2;
            mRect.top = (mHeight - mTextBound.height()) / 2 - mImage.getHeight() / 2;
            mRect.bottom = (mHeight - mTextBound.height()) / 2 + mImage.getHeight() / 2;
            canvas.drawBitmap(mImage, null, mRect, mPaint);
        }
    }

代码,结合注释和第一篇View的使用,应该可以看懂,不明白的可以留言。下面我们引入我们的自定义View:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:image="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_custom_image_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
 tools:context="com.example.jingbin.customview.activity.CustomImageViewActivity">

    <!--字体的宽度大于图片,且View宽度设置为wrap_content-->
    <com.example.jingbin.customview.view.CustomImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:padding="10dp"
        image:image="@drawable/custom_img"
        image:imageScaleType="fillXY"
        image:imageTitleText="hello android!"
        image:imageTitleTextColor="@color/colorPrimary"
        image:imageTitleTextSize="40sp" />

    <!--View宽度设置为精确值,字体的长度大于此宽度-->
    <com.example.jingbin.customview.view.CustomImageView
        android:layout_width="150dp"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:padding="10dp"
        image:image="@drawable/custom_img"
        image:imageScaleType="center"
        image:imageTitleText="hello android!"
        image:imageTitleTextColor="@color/colorPrimary"
        image:imageTitleTextSize="40sp" />

    <!--图片的宽度大于字体,且View宽度设置为wrap_content-->
    <com.example.jingbin.customview.view.CustomImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:padding="10dp"
        image:image="@drawable/custom_img"
        image:imageScaleType="center"
        image:imageTitleText="he"
        image:imageTitleTextColor="@color/colorPrimary"
        image:imageTitleTextSize="40sp" />

</LinearLayout>

我特意让显示出现3中情况:

  • 1、字体的宽度大于图片,且View宽度设置为wrap_content
  • 2、View宽度设置为精确值,字体的长度大于此宽度
  • 3、图片的宽度大于字体,且View宽度设置为wrap_content

看看显示效果:

怎么样,对于这三种情况所展示的效果都还不错吧~

源码点击此处查看

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部