zoukankan      html  css  js  c++  java
  • 自定义圆角图片控件(Xfermode方式)

    苹果都放弃自己的棱角了。。。

    看惯了方方正正的图片,乍一看到圆角图片觉得挺漂亮的。可当满世界都是圆角图片的时候,我又开始怀念那些棱角了~之前仓促的写过一个,今天拿过来又修改了一下,现在贴在这里,以方便以后ctrl+c、ctrl+v~~~~~

    一、目标

        自定义一个图片控件,有圆形和圆角两种选择。控件的行为和ImageView一致

    二、思路

        扩展ImageView控件,重写其onDraw方法。一开始还想重写onMeasure方法,如果显示圆形图片强制宽高相等,没能行得通(代码中会说明)。圆角图片以Xfermode方式实现,关于这个知识点大家可以参考这篇文章《setXfermode属性》。

    三、实现

        控件类RoundImageView:

    /**
     * 圆角或者圆形图片控件扩展自ImageView<br/>
     * 说明:<br/>
     * 1.仅重写了绘制流程,即onDraw()方法<br/>
     * 2.如果使用圆形图片需要设置固定的尺寸
     * 3.支持普通、圆形、圆角三种样式
     * 4.可设置圆角半径  默认是10dp
     * 5.无法为背景添加圆角
     * Created by 95 on 2016/1/11.
     */
    public class RoundImageView extends ImageView
    {
        private static final String TAG = RoundImageView.class.getSimpleName();
        private Paint mPaint;
        private WeakReference<Bitmap> mWeakBitmap;
    
        /**
         * 图片的类型,圆形or圆角
         */
        private int type;
        public static final int TYPE_NORMAL = 0;
        public static final int TYPE_CIRCLE = 1;
        public static final int TYPE_ROUND = 2;
    
        /**
         * 圆角大小的默认值
         */
        private static final int DEFAULT_RADIUS = 10;
        /**
         * 圆角的大小
         */
        private int mRadius;
    
        public RoundImageView(Context context)
        {
            this(context, null);
        }
    
        public RoundImageView(Context context, AttributeSet attrs)
        {
            super(context, attrs);
    
            mPaint = new Paint();
            mPaint.setAntiAlias(true);
    
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RoundImageView);
    
            mRadius = a.getDimensionPixelSize(R.styleable.RoundImageView_radius, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_RADIUS, getResources().getDisplayMetrics()));// 默认为10dp
            type = a.getInt(R.styleable.RoundImageView_type, TYPE_NORMAL);// 默认为normal
            a.recycle();
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
        {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    
            /**
             * 如果类型是圆形,则强制改变view的宽高一致,以小值为准
             * 这种写法是有问题的
             * 我们本来是想在正常测量的基础上取最短边
             * 可下面的操作插入到了正常执行的流程当中   致使最终的结果出了问题
             */
            //        if (type == TYPE_CIRCLE)
            //        {
            //            int min = Math.min(getMeasuredWidth(), getMeasuredHeight());
            //            setMeasuredDimension(min, min);
            //        }
        }
    
        @Override
        protected void onDraw(Canvas canvas)
        {
            //普通模式  调用原生的绘制方法
            if (type == TYPE_NORMAL)
            {
                super.onDraw(canvas);
                return;
            }
            //如果当前未设置图片  直接返回
            if (getDrawable() == null) return;
            //在缓存中取出bitmap
            Bitmap bitmap = mWeakBitmap == null ? null : mWeakBitmap.get();
            //如果bitmap已经被回收,就重新创建
            if (bitmap == null || bitmap.isRecycled())
            {
                bitmap = createDesiredBitmap(drawableToBitmap(getDrawable()), type, getMeasuredWidth(), getMeasuredHeight(), mRadius);
                mWeakBitmap = new WeakReference<Bitmap>(bitmap);
            }
            //以为我们所有的绘制使用了同一个Paint  所以每次使用之前都要考虑这个状态
            mPaint.setXfermode(null);
            //把最终结果绘制到画布上
            canvas.drawBitmap(bitmap, 0.0f, 0.0f, mPaint);
        }
    
    
        /**
         * 生成圆角图片 使用Xfermode方式
         *
         * @param src           原图
         * @param type          round or circle
         * @param desiredWidth  控件的宽
         * @param desiredHeight 控件的高
         * @param radius        圆角半径
         * @return
         */
        private Bitmap createDesiredBitmap(Bitmap src, int type, int desiredWidth, int desiredHeight, int radius)
        {
            Bitmap target = Bitmap.createBitmap(desiredWidth, desiredHeight, Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(target);
            mPaint.setXfermode(null);
            if (TYPE_CIRCLE == type)
            {
                canvas.drawCircle(desiredWidth * 1.0f / 2, desiredWidth * 1.0f / 2, desiredWidth * 1.0f / 2, mPaint);
            } else
            {
                RectF rectF = new RectF(0.0f, 0.0f, desiredWidth, desiredHeight);
                canvas.drawRoundRect(rectF, radius * 1.0f, radius * 1.0f, mPaint);
            }
            //缩放比例  保证图片的宽和高大于控件的宽和高
            float ratio = Math.max(desiredWidth * 1.0f / src.getWidth(), desiredHeight * 1.0f / src.getHeight());
            Bitmap tem = getScaledBitmap(src, ratio);
            //设置Xfermode
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
            //保证控件展示的位置即为图片正中间的内容
            canvas.drawBitmap(tem, (desiredWidth - tem.getWidth()) * 1.0f / 2, (desiredHeight - tem.getHeight()) * 1.0f / 2, mPaint);
            //释放内存
            tem.recycle();
            return target;
        }
    
        /**
         * 缩放图片
         *
         * @param src   原图
         * @param ratio 缩放比例
         * @return
         */
        private Bitmap getScaledBitmap(Bitmap src, float ratio)
        {
            Matrix matrix = new Matrix();
            matrix.setScale(ratio, ratio, 0.0f, 0.0f);
            Bitmap target = Bitmap.createBitmap((int) (src.getWidth() * ratio), (int) (src.getHeight() * ratio), Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(target);
            canvas.drawBitmap(src, matrix, mPaint);
            return target;
        }
    
        /**
         * drawable 转 bitmap
         *
         * @param drawable
         * @return
         */
        private Bitmap drawableToBitmap(Drawable drawable)
        {
            if (drawable instanceof BitmapDrawable)
            {
                return ((BitmapDrawable) drawable).getBitmap();
            }
            Bitmap target = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(target);
            drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
            drawable.draw(canvas);
            return target;
        }
    }
    

         自定义属性:

        <declare-styleable name="RoundImageView">
            <attr name="type" format="enum">
                <enum name="normal" value="0"/>
                <enum name="circle" value="1"/>
                <enum name="round" value="2"/>
            </attr>
    
            <attr name="radius" format="dimension"/>
        </declare-styleable>
    

     四、使用

        直接在布局文件当中使用:

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center_horizontal"
            android:orientation="vertical">
    
            <!--原图-->
            <com.hsji.testptr.widget.RoundImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/lena"/>
    
            <!--圆角效果,圆角半径是15dp-->
            <com.hsji.testptr.widget.RoundImageView
                android:layout_width="80dp"
                android:layout_height="80dp"
                android:layout_marginTop="10dp"
                android:src="@drawable/lena"
                app:radius="15dp"
                app:type="round"/>
            
            <!--非正方形圆角效果,圆角半径60dp-->
            <com.hsji.testptr.widget.RoundImageView
                android:layout_width="120dp"
                android:layout_height="80dp"
                android:layout_marginTop="10dp"
                android:src="@drawable/lena"
                app:radius="60dp"
                app:type="round"/>
    
            <!--圆形效果-->
            <com.hsji.testptr.widget.RoundImageView
                android:layout_width="120dp"
                android:layout_height="120dp"
                android:layout_marginTop="10dp"
                android:src="@drawable/lena"
                app:type="circle"/>
        </LinearLayout>
    

     下面是效果图:

  • 相关阅读:
    ASP.NET Core 2.0 : 四. _Layout与_ViewStart
    [ASP.NET MVC 小牛之路]04
    [ASP.NET MVC 小牛之路]03
    [ASP.NET MVC 小牛之路]02
    [ASP.NET MVC 小牛之路]01
    Ext JS 4 的类系统
    生活沉思录 via 哲理小故事(一)
    ExtJS框架基础:事件模型及其常用功能
    ExtJS初探:了解 Ext Core
    ExtJS初探:在项目中使用ExtJS
  • 原文地址:https://www.cnblogs.com/hsji/p/5121698.html
Copyright © 2011-2022 走看看