• Android自定义View-圆形图片控件


    个人博客

    http://www.milovetingting.cn

    Android自定义View-圆形图片控件

    前言

    在日常开发中,圆形的图片效果还是很常见的。可以通过给Paint设置Xfermode来实现,这里简单记录如下。

    实现

    实现圆形效果的核心是PorterDuffXfermode,对于PorterDuffXfermode,这里不展开,可以查询相关资料。

    核心代码

    //绘制背景
    canvas.drawCircle(mSize / 2, mSize / 2, mSize / 2, mPaint);
    //设置模式为:显示背景层和上层的交集,且显示上层图像
    mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
    //绘制要显示的图像
    canvas.drawBitmap(mSrcBitmap, 0, 0, mPaint);
    //重置Xfermode
    mPaint.setXfermode(null);
    

    自定义属性

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="CircleView">
            <!--定义资源-->
            <attr name="src" format="reference" />
            <!--定义类型-->
            <attr name="type" format="enum">
                <!--圆形-->
                <enum name="round" value="1" />
                <!--矩形-->
                <enum name="rect" value="2" />
            </attr>
        </declare-styleable>
    </resources>
    

    自定义控件

    public class CircleView extends View {
    
        private static final int DEFAULT_SIZE = 200;
    
        private static final int DEFAULT_RADIUS = 20;
    
        private static final int TYPE_ROUND = 1;
    
        private static final int TYPE_RECT = 2;
    
        private int mSize;
    
        private int mResourceId;
    
        private int mType;
    
        private Paint mPaint;
    
        private Bitmap mSrcBitmap;
    
        public CircleView(Context context) {
            this(context, null);
        }
    
        public CircleView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public CircleView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CircleView);
            mResourceId = ta.getResourceId(R.styleable.CircleView_src, R.mipmap.ic_launcher);
            mType = ta.getInt(R.styleable.CircleView_type, TYPE_ROUND);
            ta.recycle();
            init();
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            int width = getMeasureSize(widthMeasureSpec);
            int height = getMeasureSize(heightMeasureSpec);
            mSize = Math.min(width, height);
            setMeasuredDimension(mSize, mSize);
        }
    
        @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            //绘制背景
            if (mSrcBitmap == null) {
                mSrcBitmap = getScaleBitmap();
            }
            if (mType == TYPE_ROUND) {
                canvas.drawCircle(mSize / 2, mSize / 2, mSize / 2, mPaint);
            } else if (mType == TYPE_RECT) {
                canvas.drawRoundRect(0, 0, mSize, mSize, DEFAULT_RADIUS, DEFAULT_RADIUS, mPaint);
            }
            //设置模式为:显示背景层和上层的交集,且显示上层图像
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
            //绘制要显示的图像
            canvas.drawBitmap(mSrcBitmap, 0, 0, mPaint);
            //重置Xfermode
            mPaint.setXfermode(null);
        }
    
        private void init() {
            //禁用硬件加速,否则可能无法绘制圆形
            setLayerType(LAYER_TYPE_HARDWARE, null);
            mPaint = new Paint();
            mPaint.setAntiAlias(true);
            mPaint.setStyle(Paint.Style.FILL);
        }
    
        private int getMeasureSize(int measureSpec) {
            int mode = MeasureSpec.getMode(measureSpec);
            int size = MeasureSpec.getSize(measureSpec);
            return mode == MeasureSpec.EXACTLY ? size : DEFAULT_SIZE;
        }
    
        /**
         * 获取缩放后的Bitmap
         *
         * @return
         */
        private Bitmap getScaleBitmap() {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeResource(getResources(), mResourceId, options);
            options.inSampleSize = calcSampleSize(options, mSize, mSize);
            options.inJustDecodeBounds = false;
            return BitmapFactory.decodeResource(getResources(), mResourceId, options);
        }
    
        /**
         * 计算缩放比例
         *
         * @param option
         * @param width
         * @param height
         * @return
         */
        private int calcSampleSize(BitmapFactory.Options option, int width, int height) {
            int originWidth = option.outWidth;
            int originHeight = option.outHeight;
            int sampleSize = 1;
            while ((originWidth = originWidth >> 1) > width && (originHeight = originHeight >> 1) > height) {
                sampleSize = sampleSize << 1;
            }
            return sampleSize;
        }
    }
    

    注意:如果没有圆形的效果,那么可能需要禁用硬件加速:setLayerType(LAYER_TYPE_HARDWARE, null)

    布局

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_horizontal"
        android:orientation="vertical"
        tools:context=".MainActivity">
    
        <com.wangyz.custom.CircleView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            app:src="@drawable/image" />
    
        <com.wangyz.custom.CircleView
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:layout_margin="10dp"
            app:src="@drawable/image" />
    
        <com.wangyz.custom.CircleView
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:layout_margin="10dp"
            app:src="@drawable/image"
            app:type="rect" />
    
    </LinearLayout>
    

    效果

    demo.png

  • 相关阅读:
    hibernate建表默认为UTF-8编码
    XML和JSON
    chrome 模拟发送请求的方法
    什么时候需要使用缓存?
    eclipse中查找类、方法及变量被引用的地方
    用户内容与商业
    2019第48周日
    ajax与重定向
    ifream
    Windows下找到JVM占用资源高的线程
  • 原文地址:https://www.cnblogs.com/milovetingting/p/13071429.html
Copyright © 2020-2023  润新知