zoukankan      html  css  js  c++  java
  • 自定义控件【圆形】圆角 BitmapShader


    关于缩放比例
            本例中,我们会为BitmapShader设置了一个matrix,目的是按比例放大或者缩小bitmap,并移动到View控件的中心,我们不会让view的宽高大于我们bitmap的宽高,只会让bitmap的宽高大于的view宽高,当然大出的区域就被裁剪掉了
    • 圆形时:设为圆形时需要注意下,因为原始图片可能是长方形,有的宽比较大,有的高比较大,那么为显示成圆形,当尺寸大于或者小于设置尺寸时,我们就要对其进行放大或者缩小。取bitmap的宽或者高的小值(因为是分子相同,所以分母的小值对于scale就是大值)作为基准,如果采用大值,缩放后肯定不能填满我们的圆形区域。然后,view的mWidth/bSize ; 得到的就是scale。
    • 圆角时:因为涉及到宽/高比例,我们分别得到宽高的scale;最终取大值(因为分子可能不同同,所以不能像圆形时取分母的小值即可),因为我们要让最终缩放完成的图片一定要大于我们的view的区域;比如:view的宽高为10*20;图片的宽高为5*20;宽高的scale分别为2和1,最终我们应该按照宽的比例放大,而不是按照高的比例缩小;因为我们需要让缩放后的图片,一定大于我们的view宽高,并保证原图比例。

    View
    public class RoundImageView extends ImageView {
        public static final int TYPE_CIRCLE = 0;
        public static final int TYPE_ROUND = 1;
        /**图片的类型,圆形or圆角,值请参考TYPE_CIRCLE或TYPE_ROUND*/
        private int viewType;
        /**圆角的大小*/
        private int roundRadiu;
        /**圆形的半径*/
        private int circleRadiu;
        /**记录圆角矩形的边界*/
        private RectF mRoundRect;
        private Paint mBitmapPaint;

        public RoundImageView(Context context) {
            this(context, null);
        }
        public RoundImageView(Context context, AttributeSet attrs) {
            super(context, attrs);
            mBitmapPaint = new Paint();
            mBitmapPaint.setAntiAlias(true);
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundImageView);
            roundRadiu = typedArray.getDimensionPixelSize(R.styleable.RoundImageView_borderRadius, dp2px(10));//默认为10dp
            viewType = typedArray.getInt(R.styleable.RoundImageView_typeTYPE_CIRCLE);//默认为圆形
            //circleRadiu的大小需要在onMeasure根据测量到的宽高确定
            typedArray.recycle();
        }

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            //因为我们是直接继承ImageView(而不是继承自View),所以直接调用super方法就能正确得到实际的宽高(按ImageView默认的规则)
            if (viewType == TYPE_CIRCLE) {
                int mSize = Math.min(getMeasuredWidth(), getMeasuredHeight());
                circleRadiu = mSize / 2;
                setMeasuredDimension(mSize, mSize);//实际的大小
            }
        }

        @SuppressLint("DrawAllocation")
        @Override
        protected void onDraw(Canvas canvas) {
            Drawable drawable = getDrawable();
            if (drawable == nullreturn;
            //1、根据Bitmap要裁剪的类型,以及bitmap和view的宽高,计算Bitmap需要缩放的比例
            Bitmap bitmap = drawableToBitamp(drawable);
            float scale = calculateBitmapScale(bitmap);
            //2、为BitmapShader定义一个变换矩阵Matrix,通过Matrix对Bitmap进行缩放
            Matrix mMatrix = new Matrix();
            mMatrix.setScale(scale, scale);
            //3、通过Matrix将缩放后的Bitmap移动到View的中心位置
            float dx = getMeasuredWidth() - bitmap.getWidth() * scale;
            float dy = getMeasuredHeight() - bitmap.getHeight() * scale;
            mMatrix.postTranslate(dx / 2, dy / 2);//注意只能用一个set方法,其他的要用post或pre方法
            //4、通过BitmapShader对Bitmap进行渲染,
            BitmapShader bitmapShader = new BitmapShader(bitmap, TileMode.MIRROR, TileMode.REPEAT);//后两个参数:填充模式
            bitmapShader.setLocalMatrix(mMatrix);//由于我们已经让Bitmap的宽高一定【大于】view的宽高,所以上面的填充模式是没有任何效果的。
            mBitmapPaint.setShader(bitmapShader);
            //5、最后画出所需要的图形
            if (viewType == TYPE_ROUND) {
                // 【一】可以在这里通过getWidth、getHeight获取View的大小
                mRoundRect = new RectF(0, 0, getWidth(), getHeight());
                canvas.drawRoundRect(mRoundRectroundRadiuroundRadiumBitmapPaint);//在哪个矩形区域绘制,圆角大小
            } else {
                canvas.drawCircle(circleRadiucircleRadiucircleRadiumBitmapPaint);//圆心坐标,半径
            }
        }

        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            // 【二】也可以在这里直接使用系统帮我们测量的准确的View的大小
            //    if (viewType == TYPE_ROUND) mRoundRect = new RectF(0, 0, w, h);
            Log.i("bqt""w=" + w + "--h=" + h);
        }

        /**drawable转bitmap*/
        private Bitmap drawableToBitamp(Drawable drawable) {
            if (drawable instanceof BitmapDrawable) {
                BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
                return bitmapDrawable.getBitmap();
            }
            int drawableWidth = drawable.getIntrinsicWidth();
            int drawableHeight = drawable.getIntrinsicHeight();
            Bitmap bitmap = Bitmap.createBitmap(drawableWidth, drawableHeight, Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(bitmap);
            drawable.setBounds(0, 0, drawableWidth, drawableHeight);
            drawable.draw(canvas);
            return bitmap;
        }
        /**计算Bitmap需要缩放的比例*/
        private float calculateBitmapScale(Bitmap bitmap) {
            float scale = 1.0f;
            if (viewType == TYPE_CIRCLE) {
                int bSize = Math.min(bitmap.getWidth(), bitmap.getHeight());
                scale = circleRadiu * 2.0f / bSize;
            } else if (viewType == TYPE_ROUND) {
                // 如果Bitmap的宽或者高与view的宽高不匹配,计算出需要缩放的比例;缩放后的Bitmap的宽高,一定要【大于】view的宽高
                if (bitmap.getWidth() != getWidth() || bitmap.getHeight() != getHeight()) {
                    float scaleWidth = getWidth() * 1.0f / bitmap.getWidth();
                    float scaleHeight = getHeight() * 1.0f / bitmap.getHeight();
                    scale = Math.max(scaleWidth, scaleHeight);
                }
            }
            Log.i("bqt""缩放比例" + scale);
            return scale;
        }
        /**根据屏幕规格,将dp值转为px值*/
        public int dp2px(int dpVal) {
            return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, getResources().getDisplayMetrics());
        }

        //对外公布两个方法,用于动态修改圆角大小和type
        public void setBorderRadius(int borderRadius) {
            int pxVal = dp2px(borderRadius);
            if (roundRadiu != pxVal) {
                roundRadiu = pxVal;
                invalidate();
            }
        }
        public void setType(int type) {
            if (type != TYPE_ROUND && type != TYPE_CIRCLE) {
                type = TYPE_CIRCLE;
            }
            if (viewType != type) {
                viewType = type;
                requestLayout();
            }
        }
    }

    自定义属性
    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="RoundImageView">
            <attr name="borderRadius" format="dimension" />
            <attr name="type">
                <enum name="circle" value="0" />
                <enum name="round" value="1" />
            </attr>
        </declare-styleable>
    </resources>

    使用

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:bqt="http://schemas.android.com/apk/res/com.bqt.myview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#2000"
        android:orientation="vertical"
        android:padding="10dp" >
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_vertical"
            android:orientation="horizontal" >
            <com.bqt.myview.RoundImageView
                android:layout_width="60dp"
                android:layout_height="60dp"
                android:src="@drawable/icon"
                bqt:borderRadius="10dp"
                bqt:type="circle" />
            <com.bqt.myview.RoundImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="10dp"
                android:src="@drawable/icon" />
            <com.bqt.myview.RoundImageView
                android:layout_width="80dp"
                android:layout_height="80dp"
                android:layout_marginLeft="10dp"
                android:src="@drawable/icon" />
        </LinearLayout>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_vertical"
            android:orientation="horizontal" >
            <com.bqt.myview.RoundImageView
                android:layout_width="60dp"
                android:layout_height="60dp"
                android:src="@drawable/icon"
                bqt:borderRadius="10dp"
                bqt:type="round" />
            <com.bqt.myview.RoundImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="5dp"
                android:src="@drawable/icon"
                bqt:borderRadius="10dp"
                bqt:type="round" />
            <com.bqt.myview.RoundImageView
                android:layout_width="100dp"
                android:layout_height="50dp"
                android:layout_marginLeft="5dp"
                android:src="@drawable/icon"
                bqt:borderRadius="15dp"
                bqt:type="round" />
        </LinearLayout>
    </LinearLayout>





  • 相关阅读:
    优先队列插入、删除
    堆排序
    UVALive 2474 Balloons in a Box(枚举)
    二叉树的建立、四种遍历、求深度、求叶子结点数
    说说尾递归(转载)
    1#Two Sum(qsort用法)
    马克思:青年在选择职业时的考虑
    最要紧的是,我们首先要善良,其次是要诚实,再次是以后永远不要相互遗忘。
    多重背包优化算法
    poj2976 Dropping tests(01分数规划 好题)
  • 原文地址:https://www.cnblogs.com/baiqiantao/p/5462200.html
Copyright © 2011-2022 走看看