android 圓角圖片的實(shí)現(xiàn)和封裝

最近被人問起圓角圖片的實(shí)現(xiàn),花了一點(diǎn)時(shí)間鼓搗了下脓规,下面簡單分享下。

完整例子: RoundImage

先上效果圖

全部為圓角.jpg

頂部為圓角.jpg

底部為圓角.jpg

只有左上角為圓角.jpg

下面為主要源碼,實(shí)現(xiàn)了 Picasso 中的 Transformation 接口凉敲。

public class RoundCornersTransformation implements Transformation {

    private float mRadius;

    private DrawCornerImage mDrawCornerImage;

    private Paint mPaint;


    public RoundCornersTransformation(float radius, DrawCornerImage drawCornerImage) {
        mRadius = radius;
        mDrawCornerImage = drawCornerImage;
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
    }

    @Override
    public Bitmap transform(Bitmap source) {//這里為主要邏輯,原理可以套用在其他地方寺旺,比如 Glide
        int width = source.getWidth();
        int height = source.getHeight();
        Bitmap newSource = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(newSource);
        mPaint.setShader(new BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
        source.recycle();
        //畫圓角的邏輯代碼爷抓,交給 DrawCornerImage 接口的具體實(shí)現(xiàn)類
        mDrawCornerImage.drawCornerImage(canvas, mPaint, mRadius, width, height);
        return newSource;
    }

    @Override
    public String key() {
        return RoundCornersTransformation.class.toString();
    }
}

定義 DrawCornerImage 接口將變化的部分抽離出來

public interface DrawCornerImage {
    void drawCornerImage(Canvas canvas, Paint paint,float radius, int right, int bottom);
}

DrawTopCornerImage 為 DrawCornerImage 的一個(gè)實(shí)現(xiàn)類,負(fù)責(zé)具體的圓角邏輯:只有頂部為圓角

public class DrawTopCornerImage implements DrawCornerImage {

    @Override
    public void drawCornerImage(Canvas canvas, Paint paint, float radius, int right, int bottom) {
        //繪制一個(gè)全部圓角的矩形區(qū)域長寬分別為 right 和 bottom
        canvas.drawRoundRect(new RectF(0, 0, right, bottom), radius, radius, paint);
        //繪制一個(gè)矩形長寬分別為 right 和  bottom-radius阻塑,相當(dāng)于底部和上面對齊而高度差個(gè) radius, 和上面所繪制的并集蓝撇,即為圖片的可見區(qū)域。并集即為上部為圓角而底部是直角的一個(gè)區(qū)域
        canvas.drawRect(new RectF(0, radius, right, bottom), paint);
      
    }
}

原理簡單來講叮姑,就是所繪制區(qū)域的并集為可見區(qū)域唉地,注意是并集不是交集。

使用起來還是比較方便的:

Picasso.with(this)
                .load(R.drawable.ic_girl)
                .transform(new RoundCornersTransformation(corner, new DrawTopLeftCornerImage()))// here change draw strategy:DrawAllCornerImage ,DrawBottomCornerImage etc.
                .into(iv);

其他的圓角邏輯可以自行發(fā)揮传透,上面的原理不局限于 Picasso 完全也可以用在 Glide 或則其他地方耘沼,結(jié)合圖片庫的封裝可以對上面繼續(xù)進(jìn)行一次封裝。

有一點(diǎn)提一下如果你的 ImageView 有用 android:scaleType="centerCrop" 屬性朱盐,可能上面方法就有點(diǎn)不合適了群嗤,centerCrop 屬性會截取圖片的中心區(qū)域展示很可能圓角就不在展示范圍了。但是大多場景 UI 給出的設(shè)計(jì)尺寸和圖片比例應(yīng)該是一致的兵琳,上面的適用范圍還是很大的狂秘。

如果你想達(dá)到 centerCrop 屬性的效果骇径,也不是不可以,只是不適合封裝在 Picasso 的內(nèi)部邏輯中了者春。因?yàn)槲覀冃枰?ImageView 的寬高破衔,這其實(shí)更合適封裝成一個(gè)自定義 View。

下面還是直接以上面的代碼钱烟,寫個(gè)示例晰筛,并不合適使用在實(shí)際項(xiàng)目中,僅為了說明原理拴袭。

    @Override
    public Bitmap transform(Bitmap source) {
        float ivWidth = 600;//600  在我測試機(jī)中 ImageView 的像素大小
        float ivHeight = 600;//600 在我測試機(jī)中 ImageView 的像素大小
        int width = source.getWidth();
        int height = source.getHeight();
        //按照 ImageView 的大小創(chuàng)建一個(gè) Bitmap
        Bitmap newSource = Bitmap.createBitmap(ivWidth , ivHeight , Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(newSource);
        BitmapShader bitmapShader = new BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
        float scale;
       // ImageView 和原圖片的寬高比读第,取其大值為了放大后能夠完全覆蓋 ImageView 的大小
        scale = Math.max(ivWidth / width, ivHeight / height);
       //利用 Matrix 矩陣進(jìn)行縮放和居中操作
        mShaderMatrix.reset();
        mShaderMatrix.setScale(scale, scale);
       //將放大后的圖片向上移動,達(dá)到中心位置(實(shí)際情況根據(jù)圖片的各種大小拥刻,有可能也會在 x 軸方向進(jìn)行移動怜瞒,這里僅作示例演示)
        mShaderMatrix.postTranslate(0, -(height * scale - ivHeight) / 2.0f);
        bitmapShader.setLocalMatrix(mShaderMatrix);
        mPaint.setShader(bitmapShader);
        source.recycle();
        mDrawCornerImage.drawCornerImage(canvas, mPaint, mRadius, ivWidth, ivHeight);
        return newSource;
    }

下圖為和開源控件 RoundedImageView 的效果對比

QQ圖片20170425144636.jpg

大家閱讀它的源碼會發(fā)現(xiàn)原理是一樣的,大家有什么其他需要可以直接使用
RoundedImageView

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末般哼,一起剝皮案震驚了整個(gè)濱河市吴汪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌逝她,老刑警劉巖浇坐,帶你破解...
    沈念sama閱讀 216,692評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異黔宛,居然都是意外死亡近刘,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評論 3 392
  • 文/潘曉璐 我一進(jìn)店門臀晃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來觉渴,“玉大人,你說我怎么就攤上這事徽惋“噶埽” “怎么了?”我有些...
    開封第一講書人閱讀 162,995評論 0 353
  • 文/不壞的土叔 我叫張陵险绘,是天一觀的道長踢京。 經(jīng)常有香客問我,道長宦棺,這世上最難降的妖魔是什么瓣距? 我笑而不...
    開封第一講書人閱讀 58,223評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮代咸,結(jié)果婚禮上蹈丸,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好逻杖,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評論 6 388
  • 文/花漫 我一把揭開白布奋岁。 她就那樣靜靜地躺著,像睡著了一般荸百。 火紅的嫁衣襯著肌膚如雪闻伶。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,208評論 1 299
  • 那天管搪,我揣著相機(jī)與錄音虾攻,去河邊找鬼铡买。 笑死更鲁,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的奇钞。 我是一名探鬼主播澡为,決...
    沈念sama閱讀 40,091評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼景埃!你這毒婦竟也來了媒至?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,929評論 0 274
  • 序言:老撾萬榮一對情侶失蹤谷徙,失蹤者是張志新(化名)和其女友劉穎拒啰,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體完慧,經(jīng)...
    沈念sama閱讀 45,346評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡谋旦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了屈尼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片册着。...
    茶點(diǎn)故事閱讀 39,739評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖脾歧,靈堂內(nèi)的尸體忽然破棺而出甲捏,到底是詐尸還是另有隱情,我是刑警寧澤鞭执,帶...
    沈念sama閱讀 35,437評論 5 344
  • 正文 年R本政府宣布司顿,位于F島的核電站,受9級特大地震影響兄纺,放射性物質(zhì)發(fā)生泄漏大溜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評論 3 326
  • 文/蒙蒙 一囤热、第九天 我趴在偏房一處隱蔽的房頂上張望猎提。 院中可真熱鬧,春花似錦、人聲如沸锨苏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽伞租。三九已至贞谓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間葵诈,已是汗流浹背裸弦。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留作喘,地道東北人理疙。 一個(gè)月前我還...
    沈念sama閱讀 47,760評論 2 369
  • 正文 我出身青樓,卻偏偏與公主長得像泞坦,于是被迫代替她去往敵國和親窖贤。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評論 2 354

推薦閱讀更多精彩內(nèi)容