Android 圓角圖片RoundImageView(Canvas.drawDoubleRoundRect)

簡介

實現圓角圖片的方法有如下幾種,其中的最第三種是參考的Android圓角圖片和圓形圖片實現總結java

  1. 使用Google官方提供的控件CardView卡片式佈局,這個控件提供了圓角半徑設置和陰影效果。不過使用須要注意系統版本。
  2. 使用Glide圖片加載框架,利用其提供的RoundedCorners能夠設置圖片的圓角半徑,代碼大體以下:
val option = RequestOptions()
    		.error(R.mipmap.ic_launcher_round)
    		.transform(RoundedCorners(300))//設置圓角半徑
   
        Glide.with(userInfoAvatar)
            	.applyDefaultRequestOptions(option)
            	.load(imgUrl)
            	.into(img)
複製代碼
  1. 圖層覆蓋、以及從新繪製(BitmapShader、Xfermode、RoundedBitmapDrawable)具體細節見Android圓角圖片和圓形圖片實現總結文章寫的很好,很詳細。
  2. OutLine
  3. material包下的ShapeableImageView,這個簡直不要太好用哦。能夠實現圓角圖片甚至是異形圖片,固然也有邊框繪製。

第四第五兩個方法是評論區大佬給補充的知識,謝謝大佬!android

正文

強烈建議使用ShapeImageView,不只能夠實現四個角的控制還能控制四條邊,就能夠畫出任何想要的異形。具體怎麼實現能夠看一下個人這篇文章Android 實現佈局凹陷(MaterialShapeDrawable)canvas

OutLine

ShapeableImageView

只須要給這個View設置shapeAppearance屬性就能夠實現對角形狀的控制,以及邊框,先看一下效果:數組

左邊是圓角,右邊是「切角」markdown

<!-- layout.xml 就是在佈局中定義-->
<com.google.android.material.imageview.ShapeableImageView android:layout_width="200dp" android:layout_height="wrap_content" android:scaleType="fitXY" android:strokeWidth="10dp" android:strokeColor="@color/purple" android:src="@drawable/ic_launcher_background" app:shapeAppearance="@style/RoundAndCutImageStyle" />
複製代碼
<!-- style.xml 能夠單獨給每一個角設置屬性-->
    <style name="RoundAndCutImageStyle"> <item name="cornerFamilyTopLeft">rounded</item> <item name="cornerFamilyBottomLeft">rounded</item> <item name="cornerFamilyTopRight">cut</item> <item name="cornerFamilyBottomRight">cut</item> <item name="cornerSize">50%</item> <item name="cornerSizeBottomLeft">20dp</item> <item name="cornerSizeTopLeft">20dp</item> </style>
複製代碼

這裏須要解釋如下幾個屬性:app

  • app:sharedAppearance 給view設置style
  • app:sharedAppearanceOverlay 覆蓋view的style;用途:在系統主題下能夠設置通用的屬性,這個時候咱們須要本身定義一個特殊的屬性,就能夠經過app:sharedAppearanceOverlay來覆蓋,通用屬性分別有三個對應大中小控件的形狀控制,三個屬性以下:
<!-- 系統主題,使用這個主題的activity包含有material design的控件就會被如下屬性修飾形狀 -->
    <style name="MyAppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar"> <item name="shapeAppearanceLargeComponent">@style/ShapeAppearance.MyApp.LargeComponent</item> <item name="shapeAppearanceMediumComponent">@style/ShapeAppearance.MyApp.MediumComponent</item> <item name="shapeAppearanceSmallComponent">@style/ShapeAppearance.MyApp.SmallComponent</item> </style>
    
    <style name="ShapeAppearance.MyApp.MediumComponent" parent="ShapeAppearance.MaterialComponents.MediumComponent"> <item name="cornerFamily">cut</item> <item name="cornerSize">8dp</item> </style>
複製代碼
  • cornerFamily 這個屬性有兩個值
    • rounded 圓角
    • cut 切角
  • cornerSize 控制角的大小,能夠爲如下這些值
    • 百分比 這個不用解釋吧,就是長寬的一半,改變view大小會使得半徑隨之改變
    • dimension 就是dp、px、sp等等屬性;注意在view大小可能發生改變時儘可能不要使用百分比,這樣會讓你的view形狀跟着改變

這兩個屬性能夠單獨給每一個角設置,cornerFamilyTopLeft、cornerSizeTopLet這樣的。框架

  • strokeWidth 邊框的寬度
  • strokeColor 邊框顏色

經過BitmapShader從新繪製

我這裏我這裏一樣是使用的BitmapShader來進行從新繪製,大體思路是和那篇文章寫得同樣,可是使用了不一樣的繪製方法,而且也實現了每一個角單獨繪製不過相對上面的那篇文章會簡單一點。開始以前建議先閱讀這篇文章哦Android圓角圖片和圓形圖片實現總結👍ide

須要用到的各種方法

官網的中文翻譯 函數

  • BitmapShader 構造方法
public BitmapShader(Bitmap bitmap,TileMode tileX, TileMode tileY) 複製代碼

paint設置shader以後,當發生繪製時,就會把shader中的bitmap的內容繪製到指定的位置,大體這麼理解,有錯誤歡迎大佬指出,謝謝!oop

  • drawable轉bitmap 使用BitmapShader固然要先把drawable轉成bitmap
private fun drawableToBitmap(drawable: Drawable): Bitmap {
        val bitmap = Bitmap.createBitmap(getTrulyWidth(), getTrulyHeight(), Bitmap.Config.ARGB_8888)
        val canvas = Canvas(bitmap)//將畫布目標設置爲bitmap,這樣畫布的內容就會直接畫到bitmap上
        //這裏傳入的寬高就是減去padding的值
        drawable.setBounds(0, 0, getTrulyWidth(), getTrulyHeight())
        drawable.draw(canvas)
        return bitmap
    }
    
    //其實在kotlin中存在一個擴展函數,就是使用kotlin的話直接drawable.toBitmap(...)
    fun Drawable.toBitmap( @Px width: Int = intrinsicWidth, @Px height: Int = intrinsicHeight, config: Config? = null): Bitmap
複製代碼
  • Canvas.drawDoubleRoundRect,我就是經過這個方法實現了四個角的不一樣半徑繪製以及邊框繪製。
    • 方法入口,詳細註釋都在裏面
    /** * 這個方法經過內外邊框來完成繪製,且內外邊框的四個角的圓角半徑均可控 * @param outer 外邊框的範圍 * @param inner 內邊框的範圍 * @param innerRadii、outerRadii * 這兩個float數組分別保存了內外邊框的四個角的圓角半徑 * 每一個數組須要傳入8個float,每兩個爲一組 rx,ry即圓角半徑在x,y方向的值 * @param paint 這裏我傳入的paint裏面保存着bitmapShader * 此外須要注意設置Style: * FILL將會繪製到兩個矩形(RectF)中間的內容 * STROKE,就是會把兩個邊框給繪製出來。 */
        public void drawDoubleRoundRect(@NonNull RectF outer, @NonNull float[] outerRadii, @NonNull RectF inner, @NonNull float[] innerRadii, @NonNull Paint paint) 複製代碼
    這個方法的靈活性很高,由於內外邊框均可控。

注意 內邊框不能在外邊框的外面,邊界超過外邊框會致使不繪製。邊界能夠相等

實踐

內容繪製

這裏爲了簡便沒有給畫筆設置shader,就是單純的黑色。

  1. 給外邊框設置圓角,內邊框不設置

  1. 外圓內方

  1. 外圓內圓

  1. 外邊框三圓角,內邊框很小

(這個能看見個人內邊框嗎,內邊框位於view的正中間,寬高都爲0,看不見吧,這樣就已經實現了對四個圓角的控制。)

  1. 在4的基礎上添加了shader,能夠看到當內容超過原始邊界時,不斷的賦值邊緣的顏色,說明使用了TileMode.CLAMP

這裏給出最後一個的繪製代碼

canvas.drawDoubleRoundRect(
            outRect,
            floatArrayOf(
            topLeftRadius,
            topLeftRadius,//左上角
            topRightRadius,
            topRightRadius,//右上角
            bottomRightRadius,
            bottomRightRadius,//右下角
            0f,
            0f//左下角
            ),
            //內邊框,恰好是位於中間的0X0的矩形,其實只須要保證內邊框大小爲0就好了
            RectF(outWidth/2f,outHeight/2f,outWidth/2f,outHeight/2f),
            //內邊框四角半徑
            floatArrayOf(
                0f,//rx
                0f,//ry
                0f,
                0f,
                0f,
                0f,
                0f,
                0f
            ),
             bitmapPaint//style = Paint.Style.FILL 繪製兩個矩形之間的內容;
             // bitmap.shader = BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
        )
複製代碼

拓展

探索

已知畫筆設置Paint.Style.FILL時,將會繪製兩個矩形之間的內容。那麼兩個邊框有部份內容不重合時會發生什麼呢?(雖然內邊框必須小於等於外邊框,可是當外邊框設置了圓角半徑時,就可能出現兩者存在部份內容不能重合。)

先看一下繪製的邊框:

Paint.Style.STROKE

Paint.Style.FILL

結論

Canvas.drawDoubleRoundRect 這個方法繪製兩個邊框的非交集部分的內容,正好對應PorterDuff.Mode.Xor

詳細內容能夠查看PorterDuff.Mode

結語

內容不免會有錯誤,很是歡迎你們指出,對於你們的建議和錯誤指正,我會及時修改。謝謝!

相關文章
相關標籤/搜索