android 自定义控件(二)

转自:鸿洋博客,正在学习,非常感谢!
之前已经初步了解了自定义,现在要做的是自定义View显示一张图片,下面包含图片的文本介绍。
1.自定义基本属性:

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

    <attr name="textSize" format="dimension" />
    <attr name="textTitle" format="string" />
    <attr name="textColor" format="color" />
    <attr name="img" format="reference" />
    <attr name="imgScaleType">
        <enum name="fillXY" value="0" />
        <enum name="center" value="1" />
    </attr>

    <declare-styleable name="CustomeView2">
        <attr name="textSize" />
        <attr name="textTitle" />
        <attr name="textColor" />
        <attr name="img" />
        <attr name="imgScaleType" />

    </declare-styleable>
</resources>

2.自定义控件CustomeView:



    Paint mPaintText, mPaintDraw;

    Rect textRect, imgRect;
    //定义一些基本属性
    private String mTextTitle;
    private int mTextSize;
    private int mTextColor;
    private Bitmap img;
    private int mImgScaleType;


    //最终要显示的高和宽
    private int width;
    private int height;

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

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

    public CustomeView2(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomeView2, defStyleAttr, 0);
        int n = a.getIndexCount();
        for (int i = 0; i < n; i++) {
            int attr = a.getIndex(i);
            switch (attr) {
                case R.styleable.CustomeView2_textTitle:
                    mTextTitle = a.getString(R.styleable.CustomeView2_textTitle);
                    break;
                case R.styleable.CustomeView2_textColor:
                    mTextColor = a.getColor(attr, Color.BLACK);//默认黑色字体
                    break;
                case R.styleable.CustomeView2_textSize://这里用的是px
                    mTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));//默认16sp
                    break;
                case R.styleable.CustomeView2_img:
                    img = BitmapFactory.decodeResource(getResources(), a.getResourceId(attr, 0));
                    break;
                case R.styleable.CustomeView2_imgScaleType:
                    mImgScaleType = a.getInt(attr, 0);
                    break;
            }
        }

        a.recycle();

        mPaintDraw = new Paint();
        mPaintText = new Paint();
        textRect = new Rect();
        imgRect = new Rect();
        mPaintText.setTextSize(mTextSize);
        mPaintText.getTextBounds(mTextTitle, 0, mTextTitle.length(), textRect);
    }

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

    }

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

        //绘制边框
        mPaintDraw.setStrokeWidth(1);//这个边框大小暂写死
        mPaintDraw.setAntiAlias(true);//消除锯齿
        mPaintDraw.setStyle(Paint.Style.STROKE);//空心
        mPaintDraw.setColor(mTextColor);
        canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaintDraw);


        //此时绘制的text过于长让其显示”哈哈哈哈....“
        mPaintText.setColor(mTextColor);
        if (textRect.width() > width) {


            TextPaint paint = new TextPaint(mPaintText);

            String msg = TextUtils.ellipsize(mTextTitle, paint, width - getPaddingLeft() - getPaddingRight(), TextUtils.TruncateAt.END).toString();

            //绘制textView 放在图片的上面
            //绘制的时候用的是这个方法  canvas.drawRect(title,x,y,paint);
            canvas.drawText(msg, getPaddingLeft(), getPaddingTop() + textRect.height(), paint);

            //绘制textView  放在图片的下面
            //绘制的时候用的是这个方法  canvas.drawRect(title,x,y,paint);
            canvas.drawText(msg, getPaddingLeft(), height - getPaddingBottom(), paint);

        } else {
            //绘制textView 放在图片的上面
            //绘制的时候用的是这个方法  canvas.drawRect(title,x,y,paint);
            canvas.drawText(mTextTitle, getWidth() / 2 - textRect.width() / 2 - getPaddingLeft() + getPaddingRight(), getPaddingTop() + textRect.height(), mPaintText);

            //绘制textView  放在图片的下面
            //绘制的时候用的是这个方法  canvas.drawRect(title,x,y,paint);
            canvas.drawText(mTextTitle, getWidth() / 2 - textRect.width() / 2 - getPaddingLeft() + getPaddingRight(), height - getPaddingBottom(), mPaintText);
        }

        //绘制图片的绘制区域。放在textView的下面
        imgRect.left = getPaddingLeft();
        imgRect.right = width - getPaddingRight();
        imgRect.bottom = height - getPaddingBottom() - textRect.height();
        //这个地方由于还要绘制一个textVIew 所以他的高度应该要改变
        imgRect.top = getPaddingTop() + textRect.height();//绘制图在textView
            canvas.drawBitmap(img, null, imgRect, mPaintDraw);


    }

现在的效果:这里写图片描述

这里写图片描述

然后之前设置width 为warp_content的时候会出现平铺的效果,这个时候我们需要重写OnMeasure()方法:

 int specModeWidth = MeasureSpec.getMode(widthMeasureSpec);
        int specSizeWidth = MeasureSpec.getSize(widthMeasureSpec);
        int specModeHeight = MeasureSpec.getMode(heightMeasureSpec);
        int specSizeHeight = MeasureSpec.getSize(heightMeasureSpec);
        if (specModeWidth == MeasureSpec.EXACTLY) {//match
            width = specSizeWidth;
        } else {
            //这个时候要判断是图片太长还是文字太长
            int imgWidth = getPaddingLeft() + img.getWidth() + getPaddingRight();
            int textWidth = getPaddingLeft() + textRect.width() + getPaddingRight();

            //在其设置为wrap_content的时候
            if (specModeWidth == MeasureSpec.AT_MOST) {//会由子控件的宽度觉得
                int desireWidth = Math.max(imgWidth, textWidth);

                //这个时候,子控件设置的宽wrap_content,最终的宽会由父控件和自控件的宽的稍小值决定
                width = Math.min(desireWidth, specSizeWidth);
            }

        }

        if (specModeHeight == MeasureSpec.EXACTLY) {
            height = specSizeHeight;
        } else {
            int desireHeight = getPaddingBottom() + img.getHeight() + getPaddingTop() + textRect.height();
            if (specModeHeight == MeasureSpec.AT_MOST) {
                height = Math.min(desireHeight, specSizeHeight);
            }

        }
        setMeasuredDimension(width, height);
        Log.i("yqy", getMeasuredHeight() + "," + getMeasuredWidth());

这个时候的效果是:
这里写图片描述

然后我们发现之前定义的imgStyleType我们并没有使用,这个又是做什么的呢?这个是用来区分绘制的图片是否是平铺还是中心显示,这个我们在OnDraw方法里面实现:


        if (mImgScaleType == 0) {//平铺

            canvas.drawBitmap(img, null, imgRect, mPaintDraw);
        } else {//中心显示
            imgRect.left = width / 2 - imgRect.width() / 2;
            imgRect.right = width / 2 + imgRect.width() / 2;
            imgRect.top = height / 2 + (textRect.height() / 2) * 2 - imgRect.height() / 2;
            imgRect.bottom = height / 2 - (textRect.height() / 2) * 2 + imgRect.height() / 2;

            canvas.drawBitmap(img, null, imgRect, mPaintDraw);
        }

效果图:
这里写图片描述于上面一张图对比有没有发现图片的显示不一样?这就是imgStyleType的效果。

笔记总结:
1.代码编写的时候加上一个textView 让自己熟悉一下计算什么的
2.中间出现一个错误:

 Caused by: android.content.res.Resources$NotFoundException: File #009933 from drawable resource ID #0x0: .xml extension required

原因是属性styleable.xml中

<attr name="textColor" format="color" />

color属性我写成了string
3. ondraw中不要new 对象,耗内存这个要修改优化。
以上。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值