1. 程式人生 > >Android 自定義View實現圓形切圖的效果

Android 自定義View實現圓形切圖的效果

使用自定義View實現圓形ImageView的效果
這裡寫圖片描述

目前圓形邊框還需要調整,這裡有點問題

實現思路

使用一個Paint,將得到的Bitmap設定成paint的Shader,設定完成後,使用Matrix調整圖片至居中,使用RectF約束邊框,最後完成繪製

初始化Paint,設定Shader


    private void init() {
        getBitmapFromDrawable();
        if (mBitmap == null) {
            return;
        }
        mShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

        // bitmap paint
mFillPaint = new Paint(); mFillPaint.setAntiAlias(true); mFillPaint.setStyle(Paint.Style.FILL); mFillPaint.setShader(mShader); // border paint mBoundPaint = new Paint(); mBoundPaint.setAntiAlias(true); mBoundPaint.setStyle(Paint.Style.STROKE); mBoundPaint.setStrokeWidth(mBorderWidth); mBoundPaint.setColor(mBorderColor); // border rectF
mBorderBound.set(calculateBitmapBound()); // bitmap rectF mBitmapBound.set(calculateBitmapBound()); mBitmapBound.inset(mBorderWidth - 10, mBorderWidth - 10); updateShaderMatrix(); }

獲取Drawable


    private Bitmap getBitmapFromDrawable() {
        Drawable drawable = getDrawable();
        if
(drawable instanceof BitmapDrawable) { mBitmap = ((BitmapDrawable) drawable).getBitmap(); mBitmapWidth = mBitmap.getWidth(); mBitmapHeight = mBitmap.getHeight(); return mBitmap; } return null; }

計算邊距


    /**
     * 計算Bitmap邊距
     */
    private RectF calculateBitmapBound() {
        int availableWidth = getWidth() - getPaddingLeft() - getPaddingRight();
        int availableHeight = getHeight() - getPaddingTop() - getPaddingBottom();
        int sideLength = Math.min(availableWidth, availableHeight); // 可用的直徑
        mRadius = sideLength / 2;

        int left = getPaddingLeft() + (availableWidth - sideLength) / 2;
        int top = getPaddingTop() + (availableHeight - sideLength) / 2;

        Log.d(TAG, "calculateBitmapBound: left >>> " + left + " top >>> " + top + " right >>> "
                + (left + sideLength) + " right >>> " + top + " bottom >>> " + (top + sideLength));
        return new RectF(left, top, left + sideLength, top + sideLength);
    }

調整Matrix,防止只顯示圖片邊角


    /**
     * 調整圖片縮放,目前只支援CenterCrop
     */
    private void updateShaderMatrix() {
        float scale;
        float dx = 0;
        float dy = 0;

        mShaderMatrix.set(null);

        // 調整縮放,使圖片居中
        if (mBitmapWidth * mBitmapBound.height() > mBitmapBound.width() * mBitmapHeight) {
            scale = mBitmapBound.height() / (float) mBitmapHeight;
            dx = (mBitmapBound.width() - mBitmapWidth * scale) * 0.5f;
        } else {
            scale = mBitmapBound.width() / (float) mBitmapWidth;
            dy = (mBitmapBound.height() - mBitmapHeight * scale) * 0.5f;
        }

        Log.d(TAG, "updateShaderMatrix: scale >>> " + scale);
        mShaderMatrix.setScale(scale, scale);
        // TODO: 16-10-15 http://chroya.iteye.com/blog/713869
        // 回到中心點,便於下次縮放
        mShaderMatrix.postTranslate((int) (dx + 0.5f) + mBitmapBound.left, (int) (dy + 0.5f) + mBitmapBound.top);

        mShader.setLocalMatrix(mShaderMatrix);
    }

onDraw

 @Override
    protected void onDraw(Canvas canvas) {
        if (mBitmap == null) {
            super.onDraw(canvas);
        }
        Log.d(TAG, "onDraw: centerX >>> " + mBitmapBound.centerX() + " centerY >>> " + mBitmapBound.centerY());
        canvas.drawCircle(mBitmapBound.centerX(), mBitmapBound.centerY(), mRadius, mFillPaint);
        // 繪製邊框
        canvas.drawCircle(mBorderBound.centerX(), mBorderBound.centerY(), mRadius, mBoundPaint);
    }

完整程式碼


/**
 * Created by shixi_tianrui1 on 16-10-7.
 * 顯示圓形圖片的ImageView
 */

public class CircleImageView extends ImageView {

    private static final String TAG = "LOGGER";

    private BitmapShader mShader;
    private Paint mFillPaint; // 繪圖
    private Paint mBoundPaint; // 繪製圓邊

    private Bitmap mBitmap;
    private Drawable mDrawable;

    private int mBorderColor;       // 邊框顏色
    private float mBorderWidth;     // 邊框寬度

    private RectF mBorderBound = new RectF();
    private RectF mBitmapBound = new RectF();
    private Matrix mShaderMatrix = new Matrix();

    private int mRadius;
    private int mBitmapWidth;
    private int mBitmapHeight;

    private static final float DEFAULT_BORDER_WIDTH = 5;

    public CircleImageView(Context context) {
        this(context, null);
    }

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

    public CircleImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray a = getResources().obtainAttributes(attrs, R.styleable.CircleImageView);
        mBorderColor = a.getColor(R.styleable.CircleImageView_borderColor, Color.BLUE);
        mBorderWidth = a.getDimension(R.styleable.CircleImageView_borderWidth, DEFAULT_BORDER_WIDTH);
        mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_borderWidth, 20);
        a.recycle();
    }

    private void init() {
        getBitmapFromDrawable();
        if (mBitmap == null) {
            return;
        }
        mShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

        // bitmap paint
        mFillPaint = new Paint();
        mFillPaint.setAntiAlias(true);
        mFillPaint.setStyle(Paint.Style.FILL);
        mFillPaint.setShader(mShader);

        // border paint
        mBoundPaint = new Paint();
        mBoundPaint.setAntiAlias(true);
        mBoundPaint.setStyle(Paint.Style.STROKE);
        mBoundPaint.setStrokeWidth(mBorderWidth);
        mBoundPaint.setColor(mBorderColor);

        // border rectF
        mBorderBound.set(calculateBitmapBound());

        // bitmap rectF
        mBitmapBound.set(calculateBitmapBound());
        mBitmapBound.inset(mBorderWidth - 10, mBorderWidth - 10);
        updateShaderMatrix();

    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        init();
    }

    /**
     * 計算Bitmap邊距
     */
    private RectF calculateBitmapBound() {
        int availableWidth = getWidth() - getPaddingLeft() - getPaddingRight();
        int availableHeight = getHeight() - getPaddingTop() - getPaddingBottom();
        int sideLength = Math.min(availableWidth, availableHeight); // 可用的直徑
        mRadius = sideLength / 2;

        int left = getPaddingLeft() + (availableWidth - sideLength) / 2;
        int top = getPaddingTop() + (availableHeight - sideLength) / 2;

        Log.d(TAG, "calculateBitmapBound: left >>> " + left + " top >>> " + top + " right >>> "
                + (left + sideLength) + " right >>> " + top + " bottom >>> " + (top + sideLength));
        return new RectF(left, top, left + sideLength, top + sideLength);
    }


    private Bitmap getBitmapFromDrawable() {
        Drawable drawable = getDrawable();
        if (drawable instanceof BitmapDrawable) {
            mBitmap = ((BitmapDrawable) drawable).getBitmap();
            mBitmapWidth = mBitmap.getWidth();
            mBitmapHeight = mBitmap.getHeight();
            return mBitmap;
        }
        return null;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (mBitmap == null) {
            super.onDraw(canvas);
        }
        Log.d(TAG, "onDraw: centerX >>> " + mBitmapBound.centerX() + " centerY >>> " + mBitmapBound.centerY());
        canvas.drawCircle(mBitmapBound.centerX(), mBitmapBound.centerY(), mRadius, mFillPaint);
        // 繪製邊框
        canvas.drawCircle(mBorderBound.centerX(), mBorderBound.centerY(), mRadius, mBoundPaint);
    }


    /**
     * 調整圖片縮放,目前只支援CenterCrop
     */
    private void updateShaderMatrix() {
        float scale;
        float dx = 0;
        float dy = 0;

        mShaderMatrix.set(null);

        // 調整縮放,使圖片居中
        if (mBitmapWidth * mBitmapBound.height() > mBitmapBound.width() * mBitmapHeight) {
            scale = mBitmapBound.height() / (float) mBitmapHeight;
            dx = (mBitmapBound.width() - mBitmapWidth * scale) * 0.5f;
        } else {
            scale = mBitmapBound.width() / (float) mBitmapWidth;
            dy = (mBitmapBound.height() - mBitmapHeight * scale) * 0.5f;
        }

        Log.d(TAG, "updateShaderMatrix: scale >>> " + scale);
        mShaderMatrix.setScale(scale, scale);
        // TODO: 16-10-15 http://chroya.iteye.com/blog/713869
        // 回到中心點,便於下次縮放
        mShaderMatrix.postTranslate((int) (dx + 0.5f) + mBitmapBound.left, (int) (dy + 0.5f) + mBitmapBound.top);

        mShader.setLocalMatrix(mShaderMatrix);
    }
}

目前仍有點問題,解決後會及時更新

相關推薦

Android 定義View實現圓形效果

使用自定義View實現圓形ImageView的效果 目前圓形邊框還需要調整,這裡有點問題 實現思路 使用一個Paint,將得到的Bitmap設定成paint的Shader,設定完成後,使用Matrix調整圖片至居中,使用RectF約束邊框,最後完成

Android 定義View實現圓形環繞效果

之前專案中需要實現一個四周環繞中心圓形頭像的效果,感覺還是自定義比較方便,於是就自己封裝了一個控制元件去實現。先貼張圖顯示最終效果。 首先自定義一個View繼承自LinearLayout,通過動態新增childView的方式將子控制元件新增到View中。思路是先新增中間圓形頭像

Android 定義View實現圓形進度條 深入理解onDraw和onMeasure及定義屬性

Android的View類是使用者介面的基礎構件,表示螢幕上的一塊矩形區域,負責這個區域的繪製和事件處理。自定義View的過程主要包括重寫onDraw及onMeasure方法 , 其中onMeasure方法的作用就是計算出自定義View的寬度和高度。這個計算的過

Android定義View實現類似水波擴散效果

自定義View一共分為6步第一步public SpreadView(Context context) { this(context,null,0); } public SpreadView(Context context, @Nullable AttributeSe

Android定義View實現類似車來了軌跡

總體分析下:水平方向recyclewview,item包含定位點,站臺位置和站臺名稱。 下面看實現: 1.繼承framelayout,實現構造方法: public class BusStopPlateView extends FrameLayout { ... public

Android定義View實現簡單的折線、柱狀

首先說第一個柱狀圖,實現很簡單。一個自定義View,重現裡面的OnDraw方法。然後利用paint,canvas繪製帶填充的長方形即可。每個長方形的X軸平方View的x軸即可,長方形的高度通過簡單的計算即可得到。下面上柱狀圖程式碼 package com.hrules.

android定義View,實現折線(二)

效果圖: LineChartView類: public class LineChartView extends View { private int width; private int height; private float maxVal

Android -- 定義view實現keep歡迎頁倒計時效果

super onfinish -m use new getc awt ttr alt 1,最近打開keep的app的時候,發現它的歡迎頁面的倒計時效果還不錯,所以打算自己來寫寫,然後就有了這篇文章。 2,還是老規矩,先看一下我們今天實現的效果   相較於我們常見的倒計時

Android定義View——實現水波紋效果類似剩余流量球

string 三個點 pre ber block span 初始化 move 理解 最近突然手癢就想搞個貝塞爾曲線做個水波紋效果玩玩,終於功夫不負有心人最後實現了想要的效果,一起來看下吧: 效果圖鎮樓 一:先一步一步來分解一下實現的過程 需要繪制一個正弦曲線(sin

Android定義view實現圖片選色器

https://www.jb51.net/article/141336.htm 這篇文章主要為大家詳細介紹了Android自定義view實現圖片選色器,具有一定的參考價值,感興趣的小夥伴們可以參考一下 簡介 本文介紹該自定義view的使用及實現的方法,主要實現以下幾個功能: - 選取

定義View實現圓形進度條跳轉頁面

效果: //首先在values資料夾下建立一個attrs.xml: ?xml version=“1.0” encoding=“utf-8”?> //佈局: <?xml version="1.0" encoding="utf-8"?>

Android :定義view實現簡易的轉盤

直接先上效果圖 xml裡面的程式碼 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

Android 定義View實現拖拽效果

騰訊QQ有那種紅點拖動效果,今天就來實現一個簡單的自定義View拖動效果,再回到原處,並非完全仿QQ紅點拖動 先來看一下效果圖 簡單說一下實現步驟 1.建立一個類繼承View 2.繪製出一個

android 定義view實現圓盤抽獎的效果

廢話不多說直接上程式碼。 import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import andro

定義view實現圓形頭像功能

       個人中心是每一個app都有的模組,在個人中心中,我們常常可以看到一個圓形有邊框(無邊框)的頭像。作為一個常見的功能,今天我們把它實現一下。 1. 需求分析        這個主要分為兩部分:一個頭像邊框,一個是圓形頭像顯示,我們主要是考慮採用自定義View來

android定義View實現流式佈局

//先來一張效果圖 //自定義的控制元件 import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.

Android定義view實現載入中、載入失敗、無資料

一、概述 Android中經常在有的app中可以見到“載入中”並不是以彈出對話方塊的形式顯示的,而是佔用整個螢幕,如果載入失敗就會出現載入失敗頁面,點選載入失敗頁面中任意區域,都可以重新載入。今天就和大家一起學習如何通過自定義view的方式實現載入中、載入失敗

定義View實現圓形水波進度條

每次聽到某大牛談論自定義View,頓時敬佩之心,如滔滔江水連綿不絕,心想我什麼時候能有如此境界,好了,心動不如行動,於是我開始了自定義View之路,雖然過程有坎坷,但是結果我還是挺滿意的。我知道大牛還遙不可及,但是我已使出洪荒之力。此篇部落格記錄本人初入自定義View之路。 既

Android定義view-繪製圓形進度條

詳細可參考:http://blog.csdn.net/Beyond0525/article/details/48181345最近專案上有一些需求,需要繪製圓形的進度條滿足設計上和互動上的需求: 實現思路在畫布上直接繪製View,需要了解一下幾點 1.需要畫一個圓 2.圓圈上有

Android 定義View實現城市選擇列表

使用自定義View的方法,實現一個城市選擇列表 手指滑動時 自定義View實現側邊欄,並提供回撥介面 /** * Created by shixi_tianrui1 on 16-9-18. * 城市選擇列表側邊欄 */ public