Android实现圆形图片

一.概述

圆形图片现在越来越多应用于Android应用中, 但是用的最多的地方当属于, 头像的显示. 比如QQ, 新浪微博,微信中很多地方都是用了圆形头像,所以有必要深究一下.

二.圆形图片的实现方式

1.使用自定义控件

2.使用第三方库

下面先说第1种, 自定义控件

package com.example.kun.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.widget.ImageView;

import com.example.kun.R;

/**
 * 自定义圆形图片
 */
public class RoundAngleImageView extends ImageView {
    //定义2个画笔
    private Paint paint;
    private Paint paint2;
    private int roundWidth = 5;
    private int roundHeight = 5;
    //以下是必须实现的构造方法
    public RoundAngleImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context, attrs);
    }

    public RoundAngleImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public RoundAngleImageView(Context context) {
        super(context);
        init(context, null);
    }

    private void init(Context context, AttributeSet attrs) {
        if (attrs != null) {
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RoundAngleImageView);
            //根据像素赋值
            roundWidth = a.getDimensionPixelSize(R.styleable.RoundAngleImageView_roundWidth, roundWidth);
            roundHeight = a.getDimensionPixelSize(R.styleable.RoundAngleImageView_roundHeight, roundHeight);
        } else {
            //根据设备密度计算
            float density = context.getResources().getDisplayMetrics().density;
            roundWidth = (int) (roundWidth * density);
            roundHeight = (int) (roundHeight * density);
        }

        paint = new Paint();
        paint.setColor(Color.WHITE);
        paint.setAntiAlias(true);//设置图片抗锯齿,就是设置图片边缘锯齿感 不明显
        //设置2张图片相交的模式, 圆形覆盖 方形
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));

        paint2 = new Paint();
        paint2.setXfermode(null);
    }

    @Override
    public void draw(Canvas canvas) {
        Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Config.ARGB_8888);
        Canvas canvas2 = new Canvas(bitmap);
        super.draw(canvas2);
        drawLiftUp(canvas2);
        drawRightUp(canvas2);
        drawLiftDown(canvas2);
        drawRightDown(canvas2);
        canvas.drawBitmap(bitmap, 0, 0, paint2);
        bitmap.recycle();
    }

    private void drawLiftUp(Canvas canvas) {
        Path path = new Path();
        path.moveTo(0, roundHeight);
        path.lineTo(0, 0);
        path.lineTo(roundWidth, 0);
        path.arcTo(new RectF(
                        0,
                        0,
                        roundWidth * 2,
                        roundHeight * 2),
                -90,
                -90);
        path.close();
        canvas.drawPath(path, paint);
    }

    private void drawLiftDown(Canvas canvas) {
        Path path = new Path();
        path.moveTo(0, getHeight() - roundHeight);
        path.lineTo(0, getHeight());
        path.lineTo(roundWidth, getHeight());
        path.arcTo(new RectF(
                        0,
                        getHeight() - roundHeight * 2,
                        0 + roundWidth * 2,
                        getHeight()),
                90,
                90);
        path.close();
        canvas.drawPath(path, paint);
    }

    private void drawRightDown(Canvas canvas) {
        Path path = new Path();
        path.moveTo(getWidth() - roundWidth, getHeight());
        path.lineTo(getWidth(), getHeight());
        path.lineTo(getWidth(), getHeight() - roundHeight);
        path.arcTo(new RectF(
                getWidth() - roundWidth * 2,
                getHeight() - roundHeight * 2,
                getWidth(),
                getHeight()), 0, 90);
        path.close();
        canvas.drawPath(path, paint);
    }

    private void drawRightUp(Canvas canvas) {
        Path path = new Path();
        path.moveTo(getWidth(), roundHeight);
        path.lineTo(getWidth(), 0);
        path.lineTo(getWidth() - roundWidth, 0);
        path.arcTo(new RectF(
                        getWidth() - roundWidth * 2,
                        0,
                        getWidth(),
                        0 + roundHeight * 2),
                -90,
                90);
        path.close();
        canvas.drawPath(path, paint);
    }
}

对应的attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="RoundAngleImageView">
        <attr name="roundWidth" format="dimension" />
        <attr name="roundHeight" format="dimension" />
    </declare-styleable>
</resources>

布局文件:

<com.example.kun.widget.RoundAngleImageView
        android:id="@+id/photoView"
        android:src="@mipmap/temp"
        app:roundHeight="100dp"
        app:roundWidth="100dp"
        android:scaleType="fitXY"
        android:layout_width="200dp"
        android:layout_height="200dp" />

布局需要注意: 自定义属性必须要有,并且宽高必须为 layout_width和layout_height的一半

还有一点注意:

android:scaleType="fitXY"这个属性必须要有,否则不会实现图片圆形

java代码如下:

public class MainActivity extends AppCompatActivity {
    private RoundAngleImageView photoView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initialize();
    }

    private void initialize() {
        photoView = (RoundAngleImageView) findViewById(R.id.photoView);
    }
}

运行效果图:

以上的自定义控件多少还是有些麻烦的 ,下面搞一个稍微简单点的工具类

public class CircleTransform extends BitmapTransformation {
    public CircleTransform(Context context) {
        super(context);
    }

    @Override
    protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
        return circleCrop(pool, toTransform);
    }

    private static Bitmap circleCrop(BitmapPool pool, Bitmap source) {
        if (source == null) return null;

        int size = Math.min(source.getWidth(), source.getHeight());
        int x = (source.getWidth() - size) / 2;
        int y = (source.getHeight() - size) / 2;

        Bitmap squared = Bitmap.createBitmap(source, x, y, size, size);

        Bitmap result = pool.get(size, size, Bitmap.Config.ARGB_8888);
        if (result == null) {
            result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
        }

        Canvas canvas = new Canvas(result);
        Paint paint = new Paint();
        paint.setShader(new BitmapShader(squared, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
        paint.setAntiAlias(true);
        float r = size / 2f;
        canvas.drawCircle(r, r, r, paint);
        return result;
    }

    @Override
    public String getId() {
        return getClass().getName();
    }
}

布局如下:

<?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"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:gravity="center"
    android:layout_height="match_parent">

    <ImageView
        android:scaleType="fitXY"
        android:id="@+id/photoView"
        android:layout_width="100dp"
        android:layout_height="100dp" />
</LinearLayout>

java代码:

public class MainActivity extends AppCompatActivity {
    private ImageView photoView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initialize();
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Glide.with(MainActivity.this).load(Uri.parse("http://pic13.nipic.com/20110415/1347158_132411659346_2.jpg"))
                        .transform(new CircleTransform(MainActivity.this))
                        .placeholder(R.mipmap.ic_launcher)
                        .error(R.mipmap.ic_launcher)
                        .into(photoView);
            }
        });
    }
    private void initialize() {
        photoView = (ImageView) findViewById(R.id.photoView);
    }
}

以上代码使用GLide加载图片,需要引入glide库

运行截图:

分割线---------------------------------------------------------------------------------------------------------------------

以上方式虽然能实现图片圆形化,但是都是比较麻烦的,下面介绍一种我最常用的,也是最简单的一个方法

CircleImageView 

github:https://github.com/hdodenhof/CircleImageView

直接上代码

<?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"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:gravity="center"
    android:layout_height="match_parent">

    <!--加入了边框宽度和颜色-->
    <de.hdodenhof.circleimageview.CircleImageView
        app:civ_border_width="2dp"
        app:civ_border_color="#FFFFFF"
        android:id="@+id/photoView"
        android:src="@mipmap/ic_launcher"
        android:layout_width="100dp"
        android:layout_height="100dp" />
</LinearLayout>
public class MainActivity extends AppCompatActivity {
    private CircleImageView photoView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initialize();
        Picasso.with(this).load(R.mipmap.temp).into(photoView);
    }

    private void initialize() {
        photoView = (CircleImageView) findViewById(R.id.photoView);
    }
}

引入的库文件

compile 'de.hdodenhof:circleimageview:2.0.0'
compile 'com.squareup.picasso:picasso:2.5.2'
运行截图:最外层带有一个白色边框


原文地址:https://www.cnblogs.com/android-zcq/p/5138462.html