Android自定義View學習之圓角圖片(圓形圖片)

圓形圖片的實現方式有很多種,首先我分享下自己所知道的一種實現方式,這種方式的實現對角度的控制很靈活,可以在xml中自由的設置,實現的過程中使用到了PorterDuffXfermode這個類,網絡上對PorterDuffXfermode的解釋:

類android.graphics.PorterDuffXfermode繼承自android.graphics.Xfermode。在用Android中的Canvas進行繪圖時,可以通過使用PorterDuffXfermode將所繪製的圖形的像素與Canvas中對應位置的像素按照一定規則進行混合,形成新的像素值,從而更新Canvas中最終的像素顏色值,這樣會創建很多有趣的效果。當使用PorterDuffXfermode時,需要將其作爲參數傳給Paint.setXfermode(Xfermode xfermode)方法,這樣在用該畫筆paint進行繪圖時,Android就會使用傳入的PorterDuffXfermode,如果不想再使用Xfermode,那麼可以執行Paint.setXfermode(null)。

我的理解是canva在繪製倆個圖像有重疊時,會以什麼樣的形式顯示出來,只需要取決於你給它傳入的什麼模式就行了(其中總共16種模式,十六種模式圖像網絡上也有);PorterDuffXfermode功能挺強大的,想了解可以百度

效果圖:

一、該自定義View同樣繼承ImageView,重寫onDraw方法

 @Override
    protected void onDraw(Canvas canvas) {
        //創建同等大小的位圖
        Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_4444);
        //創建帶有位圖的畫布
        mCanvas=new Canvas(bitmap);
        super.onDraw(mCanvas);
        //繪製矩形內接圓(橢圓)外部分,簡單就是去掉的四個角所組成的圖形
        drawGraphical();
        canvas.drawBitmap(bitmap,0,0,mPaintBitmap);
    }
代碼中創建了一個帶有位圖的畫布,以參數的形式,通過super.onDraw(mCanvas)傳給父類,我的理解是相當於兩個畫布mCanvas和canvas重疊在一起,mCanvas在上面,各自在自己上面繪製圖形,上面的PorterDuffXfermode就使用在mCanvas上,來約束mCanvas繪製顯示的區域


private void drawGraphical() {
        //限制mRadius值的規範性
        checkRadius();
        //左上
        mPath.moveTo(0, mRadius);
        mPath.lineTo(0, 0);
        mPath.lineTo(mRadius, 0);
        //圓弧路徑
        mPath.arcTo(new RectF(0, 0, mRadius * 2, mRadius * 2), 270, -90);

        //左下
        mPath.moveTo(0, getHeight() - mRadius);
        mPath.lineTo(0, getHeight());
        mPath.lineTo(mRadius, getHeight());
        mPath.arcTo(new RectF(0, getHeight() - mRadius * 2, mRadius * 2, getHeight()), 90, 90);

        //右下
        mPath.moveTo(getWidth() - mRadius, getHeight());
        mPath.lineTo(getWidth(), getHeight());
        mPath.lineTo(getWidth(), getHeight() - mRadius);
        mPath.arcTo(new RectF(getWidth() - mRadius * 2, getHeight() - mRadius * 2, getWidth(), getHeight()), 0, 90);

        //右上
        mPath.moveTo(getWidth(), mRadius);
        mPath.lineTo(getWidth(), 0);
        mPath.lineTo(getWidth() - mRadius, 0);
        mPath.arcTo(new RectF(getWidth() - mRadius * 2, 0, getWidth(),mRadius * 2), 270, 90);
        mCanvas.drawPath(mPath, mPaintPath);
    }
繪製需要遮擋的圖形區域,moveTo(x,y)從哪個點開始,lineTo(x,y)到哪個點,arcTo(new RectF())繪製圓弧路徑,drawPath()根據規定的路徑開始繪製,繪製完,大概的樣子就是一個矩形去掉內接圓(長和寬相等)剩下的部分就是的了,自己不會畫圖,自己想象下吧


private void init(Context context, AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CornerImageView);
        mRadius = typedArray.getDimension(R.styleable.CornerImageView_cornerRadius, -1);
        mPaintBitmap=new Paint();
        mPaintBitmap.setAntiAlias(true);
        mPaintPath=new Paint();
        mPaintPath.setAntiAlias(true);
        mPorterDuffXfermode=new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
        mPaintPath.setXfermode(mPorterDuffXfermode);
        //圖形對象
        mPath=new Path();
    }
初始化代碼,
PorterDuff.Mode.DST_OUT
取底部相交圖形之外的部分


二、全部代碼

package com.yufs.myimageview.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
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.yufs.myimageview.R;

/**
 * Created by yufs on 2017/5/22.
 */

public class CornerImageView extends ImageView{
    private Canvas mCanvas;
    private Paint mPaintBitmap;//繪製bitmap的畫筆
    private Paint mPaintPath;//繪製path的畫筆
    private Path mPath;//path對象
    private float mRadius=0;//圓角弧度
    private PorterDuffXfermode mPorterDuffXfermode;//
    public CornerImageView(Context context) {
        super(context);
        init(context, null);
    }

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

    public CornerImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context,attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CornerImageView);
        mRadius = typedArray.getDimension(R.styleable.CornerImageView_cornerRadius, -1);
        mPaintBitmap=new Paint();
        mPaintBitmap.setAntiAlias(true);
        mPaintPath=new Paint();
        mPaintPath.setAntiAlias(true);
        mPorterDuffXfermode=new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
        mPaintPath.setXfermode(mPorterDuffXfermode);
        //圖形對象
        mPath=new Path();
    }



    @Override
    protected void onDraw(Canvas canvas) {
        //創建同等大小的位圖
        Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_4444);
        //創建帶有位圖的畫布
        mCanvas=new Canvas(bitmap);
        super.onDraw(mCanvas);
        //繪製矩形內接圓(橢圓)外部分,簡單就是去掉的四個角所組成的圖形
        drawGraphical();
        canvas.drawBitmap(bitmap,0,0,mPaintBitmap);
    }

    private void drawGraphical() {
        //限制mRadius值的規範性
        checkRadius();
        //左上
        mPath.moveTo(0, mRadius);
        mPath.lineTo(0, 0);
        mPath.lineTo(mRadius, 0);
        //圓弧路徑
        mPath.arcTo(new RectF(0, 0, mRadius * 2, mRadius * 2), 270, -90);

        //左下
        mPath.moveTo(0, getHeight() - mRadius);
        mPath.lineTo(0, getHeight());
        mPath.lineTo(mRadius, getHeight());
        mPath.arcTo(new RectF(0, getHeight() - mRadius * 2, mRadius * 2, getHeight()), 90, 90);

        //右下
        mPath.moveTo(getWidth() - mRadius, getHeight());
        mPath.lineTo(getWidth(), getHeight());
        mPath.lineTo(getWidth(), getHeight() - mRadius);
        mPath.arcTo(new RectF(getWidth() - mRadius * 2, getHeight() - mRadius * 2, getWidth(), getHeight()), 0, 90);

        //右上
        mPath.moveTo(getWidth(), mRadius);
        mPath.lineTo(getWidth(), 0);
        mPath.lineTo(getWidth() - mRadius, 0);
        mPath.arcTo(new RectF(getWidth() - mRadius * 2, 0, getWidth(),mRadius * 2), 270, 90);
        mCanvas.drawPath(mPath, mPaintPath);
    }

    /**
     * 如果未設置cornerRadius屬性,或者設置的非法,默認是圓形
     */
    private void checkRadius() {
        float minValues;
        if(getWidth()>getHeight()){
            minValues=getHeight();
        }else{
            minValues=getWidth();
        }
        if(mRadius>minValues/2||mRadius<0){
            mRadius=minValues/2;
        }
    }
}

attrs文件

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

xml中使用

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:mimage="http://schemas.android.com/apk/res-auto"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.yufs.myimageview.MainActivity">
    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <LinearLayout
            android:layout_width="match_parent"
            android:orientation="vertical"
            android:gravity="center_horizontal"
            android:layout_height="wrap_content">

            <com.yufs.myimageview.view.CornerImageView
                android:layout_width="150dp"
                android:layout_height="50dp"
                android:layout_marginTop="24dp"
                android:scaleType="centerCrop"
                android:src="@mipmap/green"
                mimage:cornerRadius="12dp"
                />

            <com.yufs.myimageview.view.CornerImageView
                android:layout_width="90dp"
                android:layout_height="90dp"
                android:layout_marginTop="12dp"
                android:scaleType="centerCrop"
                android:src="@mipmap/green"
                />


            <com.yufs.myimageview.view.CornerImageView
                android:layout_width="90dp"
                android:layout_height="90dp"
                android:layout_marginTop="12dp"
                android:scaleType="centerCrop"
                mimage:cornerRadius="12dp"
                android:src="@mipmap/green"
                />

            <com.yufs.myimageview.view.CornerImageView
                android:layout_width="120dp"
                android:layout_height="45dp"
                android:layout_marginTop="12dp"
                android:scaleType="centerCrop"
                android:src="@mipmap/green"
                />
        </LinearLayout>
    </ScrollView>



</RelativeLayout>

使用自定義屬性時別忘記在頂部加入聲明

xmlns:mimage="http://schemas.android.com/apk/res-auto"
mimage名字隨意

green是一張圖片,你可以用自己的演示看看,有什麼問題,或者我說的有哪不對的,希望大神幫忙指點下,謝謝



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章