自定義View:自定義CircleImageView實現及圖形渲染
在很多應用中頭像是以圓形圖片展示的,預設圖片的話可以讓UI切一套圓形的,但是使用者設定頭像的話不可能也讓UI切。其實已經有很多前輩牛人已經寫了成熟完善的工具類供程式猿使用。當然實現方式也多種多樣。這裡道長使用圖形渲染實現CircleImageView,然後說一下圖形渲染的一些知識。
一、CircleImageView實現
- 構造方法初始化變數
public CircleImageView(Context context, AttributeSet attrs) {
super(context, attrs);
mMatrix = new Matrix();
mBitmapPaint = new Paint();
mBitmapPaint.setAntiAlias(true);
}
public CircleImageView(Context context) {
this(context, null);
}
- 測量並設定控制元件寬高
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = Math.min(getMeasuredWidth(), getMeasuredHeight());
mRadius = mWidth / 2 ;
setMeasuredDimension(mWidth, mWidth);
}
- 給Paint設定渲染規則
private void setPaintShader() {
Drawable drawable = getDrawable();
if (drawable == null) {
return;
}
Bitmap bitmap = drawable2Bitmap(drawable);
// 建立Bitmap渲染物件
mBitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
float scale = 1.0f;
// 比較bitmap寬和高,獲得較小值
int bSize = Math.min(bitmap.getWidth(), bitmap.getHeight());
scale = mWidth * 1.0f / bSize;
// shader的變換矩陣,用於放大或者縮小
mMatrix.setScale(scale, scale);
// 設定變換矩陣
mBitmapShader.setLocalMatrix(mMatrix);
// 設定shader
mBitmapPaint.setShader(mBitmapShader);
}
/**
* drawable轉bitmap
*
* @param drawable
* @return
*/
private Bitmap drawable2Bitmap(Drawable drawable) {
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bd = (BitmapDrawable) drawable;
return bd.getBitmap();
}
int w = drawable.getIntrinsicWidth();
int h = drawable.getIntrinsicHeight();
Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, w, h);
drawable.draw(canvas);
return bitmap;
}
- 在畫布上繪製圖片
@Override
protected void onDraw(Canvas canvas) {
if (getDrawable() == null) {
return;
}
try {
setPaintShader();
canvas.drawCircle(mRadius, mRadius, mRadius, mBitmapPaint);
} catch (Exception e) {
e.printStackTrace();
}
}
- 在佈局中新增如下程式碼
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<ImageView
android:id="@+id/iv_default"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:src="@drawable/head" />
<com.yushan.picturerenderdemo.CircleImageView
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_below="@id/iv_default"
android:layout_margin="5dp"
android:src="@drawable/head" />
</RelativeLayout>
- 上面的為原圖,下面的為CircleImageView,效果圖如下
就這麼簡單,是不是so easy~當然這個程式碼中有一個弊端道長沒有處理,就是在測量設定控制元件寬高時道長只是簡單的取了一個寬高最小值,然後除以2就設定了。這就導致了CircleImageView最大隻能展示原圖大小。這個大家可以自行處理。然後我們說一下圖形渲染……
二、圖形渲染
在實現自定義CircleImageView中道長使用了圖形渲染中的影象渲染,而前面道長說過的畫布實現自定義View(折線圖實現),在繪製限制區域時道長使用的就是圖形渲染中的線性渲染。這裡道長就不貼程式碼了,前面有連結童鞋們可以去看一下。圖形渲染大概分為五種:
- BitmapShader(影象渲染)
/**
* @param bitmap 用來作為紋理填充的點陣圖
* @param tileX 在點陣圖X方向上點陣圖銜接形式
* @param tileY 在點陣圖Y方向上點陣圖銜接形式
*/
public BitmapShader(Bitmap bitmap, Shader.TileMode tileX, Shader.TileMode tileY);
Shader.TileMode有3種引數可供選擇,分別為CLAMP、REPEAT和MIRROR。
CLAMP - 如果渲染器超出原始邊界範圍,則會複製邊緣顏色對超出範圍的區域進行著色。
REPEAT - 在橫向和縱向上以平鋪的形式重複渲染點陣圖。
MIRROR - 在橫向和縱向上以映象的方式重複渲染點陣圖。
簡單使用:
/**
* 影象渲染
*
* @param canvas
* @param paint
*/
private void drawBitmapShader(Canvas canvas, Paint paint) {
// 載入影象資源
Bitmap mBitmap = ((BitmapDrawable) getResources().getDrawable(R.drawable.head)).getBitmap();
// 建立Bitmap渲染物件
Shader mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
// 繪製Bitmap渲染的圓
paint.setShader(mBitmapShader);
canvas.drawCircle(100, 100, 100, paint);
}
- LinearGradient(線性渲染)
/**
* @param x0 漸變的起始點x座標
* @param y0 漸變的起始點y座標
* @param x1 漸變的終點x座標
* @param y1 漸變的終點y座標
* @param colors 漸變的顏色陣列
* @param positions 指定顏色陣列的相對位置
* @param tile 平鋪方式
*/
public LinearGradient (float x0, float y0, float x1, float y1, int[] colors, float[] positions, Shader.TileMode tile);
注意:引數positions設為null,表示顏色陣列以斜坡線的形式均勻分佈。
簡單使用:
/**
* 線性渲染
*
* @param canvas
* @param paint
*/
private void drawLinearGradient(Canvas canvas, Paint paint) {
// 建立線性渲染物件
int mColorLinear[] = {Color.WHITE, Color.YELLOW, Color.GREEN, Color.BLUE};
Shader mLinearGradient = new LinearGradient(150, 150, 100, 100, mColorLinear, null, Shader.TileMode.REPEAT);
// 繪製線性漸變的矩形
paint.setShader(mLinearGradient);
canvas.drawRect(100, 300, 400, 500, paint);
}
- ComposeShader(混合渲染)
/**
* @param shaderA 一種渲染效果
* @param shaderB 一種渲染效果
* @param mode 兩種渲染效果的疊加模式
*/
public ComposeShader (Shader shaderA, Shader shaderB, PorterDuff.Mode mode);
PorterDuff.Mode有16種引數可供選擇,分別為:CLEAR、SRC、DST、SRC_OVER、DST_OVER、SRC_IN、DST_IN、SRC_OUT、DST_OUT、SRC_ATOP、DST_ATOP、XOR、DARKEN、LIGHTEN、MULTIPLY、SCREEN。
疊加模式的具體疊加效果如下圖所示:
簡單使用:
/**
* 混合渲染
*
* @param canvas
* @param paint
*/
private void drawComposeShader(Canvas canvas, Paint paint) {
// 建立線性渲染物件
int mColorLinear[] = {Color.WHITE, Color.YELLOW, Color.GREEN, Color.BLUE};
Shader mLinearGradient = new LinearGradient(150, 150, 100, 100, mColorLinear, null, Shader.TileMode.REPEAT);
// 建立環形渲染物件
int mColorRadial[] = {Color.GREEN, Color.RED, Color.BLUE, Color.WHITE};
Shader mRadialGradient = new RadialGradient(300, 300, 75, mColorRadial, null, Shader.TileMode.REPEAT);
//建立混合渲染物件
Shader mComposeShader = new ComposeShader(mLinearGradient, mRadialGradient, PorterDuff.Mode.DARKEN);
//繪製混合漸變(線性與環形混合)的矩形
paint.setShader(mComposeShader);
canvas.drawRect(10, 420, 250, 570, paint);
}
- RadialGradient(環形渲染)
/**
* @param x 圓心x座標
* @param y 圓心y座標
* @param radius 半徑
* @param colors 漸變的顏色陣列
* @param positions 顏色陣列的相對位置
* @param tile 平鋪的方式
*/
public RadialGradient (float x, float y, float radius, int[] colors, float[] positions, Shader.TileMode tile);
簡單使用:
/**
* 環形渲染
*
* @param canvas
* @param paint
*/
private void drawRadialGradient(Canvas canvas, Paint paint) {
// 建立環形渲染物件
int mColorRadial[] = {Color.WHITE, Color.YELLOW, Color.GREEN, Color.BLUE};
Shader mRadialGradient = new RadialGradient(500, 500, 100, mColorRadial, null, Shader.TileMode.REPEAT);
// 繪製環形漸變的圓
paint.setShader(mRadialGradient);
canvas.drawCircle(500, 500, 100, paint);
}
- SweepGradient(梯度渲染)
/**
* @param cx 掃描的中心x座標
* @param cy 掃描的中心y座標
* @param colors 漸變的顏色陣列
* @param positions 顏色陣列的相對位置
*/
public SweepGradient (float cx, float cy, int[] colors, float[] positions);
簡單使用:
/**
* 梯度渲染
*
* @param canvas
* @param paint
*/
private void drawSweepGradient(Canvas canvas, Paint paint) {
// 建立梯形渲染物件
int mColorSweep[] = {Color.GREEN, Color.RED, Color.BLUE, Color.YELLOW, Color.GREEN};
Shader mSweepGradient = new SweepGradient(650, 700, mColorSweep, null);
// 繪製梯形漸變的矩形
paint.setShader(mSweepGradient);
canvas.drawRect(600, 600, 700, 800, paint);
}
到了這裡關於自定義CircleImageView的實現以及圖形渲染已經說完了,其實道長說自定義CircleImageView是一個引子,重點是說一下圖形渲染,這個圖形渲染在自定義View中還是比較常用的。好了,希望這篇部落格能夠為你提供一些幫助。
相關推薦
自定義View:自定義CircleImageView實現及圖形渲染
在很多應用中頭像是以圓形圖片展示的,預設圖片的話可以讓UI切一套圓形的,但是使用者設定頭像的話不可能也讓UI切。其實已經有很多前輩牛人已經寫了成熟完善的工具類供程式猿使用。當然實現方式也多種多樣。這裡道長使用圖形渲染實現CircleImageView,然後說一下
自定義View:實現RecyclerView的item新增懸浮層的效果
前言 20天后,終於良心發現更新部落格了,又到了年底,好多的事情都要收尾,今天分享一個RecyclerView的容器類,幫助大家實現新增Item的浮層的效果。 首先看一下效果圖: 有人會問我:老鐵,你實現的這個東西有個卵用?如果你沒看明白,我們再看一張非常熟悉
Android 自定義View-----流式佈局(粗糙實現)
//首先檢視一下佈局介面吧 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app
自定義view系列(5)--99.99%實現QQ側滑刪除效果
首先宣告本文是基於GitHub上"baoyongzhang"的SwipeMenuListView修改而來, 可以說這個側滑刪除效果是我見過效果最好且比較靈活的專案,沒有之一!!! 但是在使用它之前需要給大家提兩點注意事項: 1,該專案支援Gradle dependence
Android自定義View:你需要一個簡單好用、含歷史搜尋記錄的搜尋框嗎?
前言 Android開發中,類似下圖的搜尋功能非常常見 今天,我將帶來一款 封裝了 歷史搜尋記錄功能 & 樣式 的Android 自定義搜尋框 開源庫,希望你們會喜歡。
Android自定義View之導航欄(Fragment實現)
安卓輕量級底部導航欄 目前安卓開發中常常會用到底部導航欄這個控制元件,但是自己從零開始做一個又太麻煩。因此,我封裝了一個底部導航欄,同時,也做了一些修改,用於頂部也十分合適。下面是示例圖: 使用方法: 1.新增依賴 首先,在build.gradle檔案下加入 maven
自定義View:View的Measure測量過程解析
相信絕大多數Android開發者都有自定義View來滿足各種各樣需求的經歷,也知道一個View的繪製展示要經過measure、layout、draw三大流程,三者中measure的過程相比是稍微複雜一點點的。這篇文章作為一個Android基礎的分享,分享
自定義View:測量measure,佈局layout,繪製draw
1. 什麼是View 在Android的官方文件中是這樣描述的:表示了使用者介面的基本構建模組。一個View佔用了螢幕上的一個矩形區域並且負責介面繪製和事件處理。 手機螢幕上所有看得見摸得著的都是View。這一點對所有圖形系統來說都一樣,例如ios的UIVi
Android自定義View——貝塞爾曲線實現水波紋進度球
效果圖 原理分析 首先需要了解的水波紋實現效果,可以在部落格的自定義View專題找到,其實現原理如下 利用貝塞爾曲線繪製螢幕外和螢幕內的sin曲線 利用path將sin曲線的左下角和右下角連線起來成為一塊區域 通過不斷的平移sin曲線,然後平移完
自定義View,貝賽爾曲線實現水波紋進度條
最終的效果: 思路就是在onDraw()中畫一些內容,主要方法有這些: /** * 剪裁圓形區域 */ clipCircle(canvas); /** * 畫圓邊線 */ drawCircle(canvas); /** * 畫波浪線 */ drawWave(
android自定義View:純canvas繪製的體重刻度尺
廢話不多說,先上效果圖 在此特別感謝扔物線的HenCoder系列,目前已更新了8章內容,讓我從一個純canvas小白變成了canvas小菜。 刻度尺效果是仿寫HenCoder公眾號中《仿寫酷介面》中的薄荷健康的滑動捲尺效果,效果圖如下: 網上已經有很多
自定義View—使用clipPath或者BitmapShader實現圓角圖片
實現圓角圖片的方式有三種,上篇文章中是使用了Xfermode,這篇文章則將總結剩下的兩種clipPath、BitmapShader。這裡我們跟上一篇一樣繼承自ImageView。 公共部分 無論是使用哪種方法,都需要自定義的屬性和在構造器中獲得相應的
一個金融類的自定義View,教大家如何實現股票軟體中的折線圖
今日科技快訊北京證監局近日釋出通告,責令樂視網前任董事長賈躍亭於2017年12月31日前回國,切
自定義view動態載入控制元件實現動態換行
自定義view動態載入控制元件 先來講下需求吧,可能我們開發中會遇到這樣的場景,需要在一個父容器里加載多個子view,但是,子view的排版又有特殊要求,比如自適應螢幕寬度或者高度等,這樣以來原本的控制元件無法滿足需要了。先看下圖的實現效果,介面有些粗糙,
自定義View(四) Graphics2D 實現動態效果
自定義動畫的動態包括兩個方面 讓動畫動起來 (這類動畫可以通過週期行重畫實現) 實現和使用者的互動 在繪圖的整個過程中,經常會使用到雙快取技術,這是一項挺重要的技術,,為什麼這麼說呢? 能提高繪圖的效率 實現繪圖的過程和結果分離 ⚠️ 理解和掌
Android自定義View:帶背景顏色的TextView和條形圖--(1)
初始: 最近在看《Android群英傳》一書,程式碼自己敲了一遍,想想之前敲了又忘記的慘痛經歷,決定在部落格上記錄自己敲的程式碼,有幾個寫幾篇,放在一個系列裡邊,就這樣,以後看就能一下子找到了。 自定義View 自定義View我們大致可以從是三個方面著手:
Android自定義View:水平帶數字百分比的進度條
public class NumberProgressView extends View { /** * 進度條畫筆的寬度(dp) */ private int paintProgressWidth = 3; /** * 文字百分比的字型大小(sp)
自定義View之自定屬性
在自定義的View中,很多時候我們需要對View新增自定義屬性步驟如下: 1) 編寫xml檔案,定義屬性名稱與屬性資料型別 //attrs.xml <resources> <declare-styleable name="MyV
Android自定義View之自定義屬性
在Android開發中經常會用到自定義View的情況,而在自定義View時,自定義屬性是必須用到的。 1、新建一個自定義View如CustomView 它的自定義屬性主要是通過declare-styleable標籤為其配置自定義屬性。具體做法是:在res/values/目錄下增加一個reso
自定義View和自定義ViewGroup一步到位
1.自定義View 首先我們要明白,為什麼要自定義View?主要是Android系統內建的View無法實現我們的需求,我們需要針對我們的業務需求定製我們想要的View。自定義View我們大部分時候只需重寫兩個函式:onMeasure()、onDraw()。onM