Android Paint Xfermode 學習小結
一、setXfermode(Xfermode xfermode)
Xfermode國外有大神稱之為過渡模式,這種翻譯比較貼切但恐怕不易理解,大家也可以直接稱之為影象混合模式,因為所謂的“過渡”其實就是影象混合的一種,這個方法跟我們上面講到的setColorFilter蠻相似的。檢視API文件發現其果然有三個子類:AvoidXfermode, PixelXorXfermode和PorterDuffXfermode,這三個子類實現的功能要比setColorFilter的三個子類複雜得多。
由於AvoidXfermode, PixelXorXfermode都已經被標註為過時了,所以這次主要研究的是仍然在使用的PorterDuffXfermode:
二、PorterDuffXfermode
該類同樣有且只有一個含參的構造方法PorterDuffXfermode(PorterDuff.Mode mode),雖說構造方法的簽名列表裡只有一個PorterDuff.Mode的引數,但是它可以實現很多酷斃的圖形效果!!而PorterDuffXfermode就是圖形混合模式的意思,其概念最早來自於SIGGRAPH的Tomas Proter和Tom Duff,混合圖形的概念極大地推動了圖形影象學的發展,延伸到計算機圖形影象學像Adobe和AutoDesk公司著名的多款設計軟體都可以說一定程度上受到影響,而我們PorterDuffXfermode的名字也來源於這倆人的人名組合PorterDuff,那PorterDuffXfermode能做些什麼呢?我們先來看一張API DEMO裡的圖片:
這張圖片從一定程度上形象地說明了圖形混合的作用,兩個圖形一圓一方通過一定的計算產生不同的組合效果,在API中Android為我們提供了18種(比上圖多了兩種ADD和OVERLAY)模式:
ADD:飽和相加,對影象飽和度進行相加,不常用
CLEAR:清除影象
DARKEN:變暗,較深的顏色覆蓋較淺的顏色,若兩者深淺程度相同則混合
DST:只顯示目標影象
DST_ATOP:在源影象和目標影象相交的地方繪製【目標影象】,在不相交的地方繪製【源影象】,相交處的效果受到源影象和目標影象alpha的影響
DST_IN:只在源影象和目標影象相交的地方繪製【目標影象】,繪製效果受到源影象對應地方透明度影響
DST_OUT:只在源影象和目標影象不相交的地方繪製【目標影象】,在相交的地方根據源影象的alpha進行過濾,源影象完全不透明則完全過濾,完全透明則不過濾
DST_OVER:將目標影象放在源影象上方
LIGHTEN:變亮,與DARKEN相反,DARKEN和LIGHTEN生成的影象結果與Android對顏色值深淺的定義有關
MULTIPLY:正片疊底,源影象素顏色值乘以目標影象素顏色值除以255得到混合後圖像畫素顏色值
OVERLAY:疊加
SCREEN:濾色,色調均和,保留兩個圖層中較白的部分,較暗的部分被遮蓋
SRC:只顯示源影象
SRC_ATOP:在源影象和目標影象相交的地方繪製【源影象】,在不相交的地方繪製【目標影象】,相交處的效果受到源影象和目標影象alpha的影響
SRC_IN:只在源影象和目標影象相交的地方繪製【源影象】
SRC_OUT:只在源影象和目標影象不相交的地方繪製【源影象】,相交的地方根據目標影象的對應地方的alpha進行過濾,目標影象完全不透明則完全過濾,完全透明則不過濾
SRC_OVER:將源影象放在目標影象上方
XOR:在源影象和目標影象相交的地方之外繪製它們,在相交的地方受到對應alpha和色值影響,如果完全不透明則相交處完全不繪製
而上面這張圖片對應的官方DEMO程式碼如下:https://android.googlesource.com/platform/development/+/master/samples/ApiDemos/src/com/example/android/apis/graphics/Xfermodes.java
public class sampleActivity extends AppCompatActivity { // create a bitmap with a circle, used for the "dst" image static Bitmap makeDst(int w, int h) { Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bm); Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); p.setColor(0xFFFFCC44); c.drawOval(new RectF(0, 0, w*3/4, h*3/4), p); return bm; } // create a bitmap with a rect, used for the "src" image static Bitmap makeSrc(int w, int h) { Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bm); Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); p.setColor(0xFF66AAFF); c.drawRect(w/3, h/3, w*19/20, h*19/20, p); return bm; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new SampleView(this)); } private static class SampleView extends View { private static final int W = 200; private static final int H = 200; private static final int ROW_MAX = 4; // number of samples per row private Bitmap mSrcB; private Bitmap mDstB; private Shader mBG; // background checker-board pattern private static final Xfermode[] sModes = { new PorterDuffXfermode(PorterDuff.Mode.CLEAR), new PorterDuffXfermode(PorterDuff.Mode.SRC), new PorterDuffXfermode(PorterDuff.Mode.DST), new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER), new PorterDuffXfermode(PorterDuff.Mode.DST_OVER), new PorterDuffXfermode(PorterDuff.Mode.SRC_IN), new PorterDuffXfermode(PorterDuff.Mode.DST_IN), new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT), new PorterDuffXfermode(PorterDuff.Mode.DST_OUT), new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP), new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP), new PorterDuffXfermode(PorterDuff.Mode.XOR), new PorterDuffXfermode(PorterDuff.Mode.DARKEN), new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN), new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY), new PorterDuffXfermode(PorterDuff.Mode.SCREEN) }; private static final String[] sLabels = { "Clear", "Src", "Dst", "SrcOver", "DstOver", "SrcIn", "DstIn", "SrcOut", "DstOut", "SrcATop", "DstATop", "Xor", "Darken", "Lighten", "Multiply", "Screen" }; public SampleView(Context context) { super(context); mSrcB = makeSrc(W, H); mDstB = makeDst(W, H); // make a ckeckerboard pattern Bitmap bm = Bitmap.createBitmap(new int[] { 0xFFFFFFFF, 0xFFCCCCCC, 0xFFCCCCCC, 0xFFFFFFFF }, 2, 2, Bitmap.Config.RGB_565); mBG = new BitmapShader(bm, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT); Matrix m = new Matrix(); m.setScale(6, 6); mBG.setLocalMatrix(m); } @Override protected void onDraw(Canvas canvas) { canvas.drawColor(Color.WHITE); Paint labelP = new Paint(Paint.ANTI_ALIAS_FLAG); labelP.setTextAlign(Paint.Align.CENTER); Paint paint = new Paint(); paint.setFilterBitmap(false); canvas.translate(15, 35); int x = 0; int y = 0; for (int i = 0; i < sModes.length; i++) { // draw the border paint.setStyle(Paint.Style.STROKE); paint.setShader(null); canvas.drawRect(x - 0.5f, y - 0.5f, x + W + 0.5f, y + H + 0.5f, paint); // draw the checker-board pattern paint.setStyle(Paint.Style.FILL); paint.setShader(mBG); canvas.drawRect(x, y, x + W, y + H, paint); // draw the src/dst example into our offscreen bitmap int sc = canvas.saveLayer(x, y, x + W, y + H, null, Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG); canvas.translate(x, y); canvas.drawBitmap(mDstB, 0, 0, paint); paint.setXfermode(sModes[i]); canvas.drawBitmap(mSrcB, 0, 0, paint); paint.setXfermode(null); canvas.restoreToCount(sc); // draw the label canvas.drawText(sLabels[i], x + W/2, y - labelP.getTextSize()/2, labelP); x += W + 10; // wrap around when we've drawn enough for one row if ((i % ROW_MAX) == ROW_MAX - 1) { x = 0; y += H + 30; } } } } }
對於上面這些mode的詳細介紹在GA_STUDIO的這篇文章和AIGESTUDIO的這篇文章都有非常詳盡的介紹
三、使用場景
以下是PorterDuffXfermode的一些使用場景:
1、自定義loading樣式:
程式碼如下:
public class LogoLoadingView extends View { private int totalW,totalH; private Paint paint; private Bitmap bitmap; private int currentTop; private RectF rectF; private PorterDuffXfermode xfermode; public LogoLoadingView(Context context) { super(context); init(); } public LogoLoadingView(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init(){ paint=new Paint(); paint.setAntiAlias(true);//設定抗鋸齒 paint.setStyle(Paint.Style.FILL);//設定填充樣式 paint.setDither(true);//設定是否使用影象抖動處理,會使繪製出來的圖片顏色更加平滑和飽滿,影象更加清晰 paint.setFilterBitmap(true);//加快顯示速度,本設定項依賴於dither和xfermode的設定 bitmap= BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);//從資原始檔中解析獲取Bitmap xfermode=new PorterDuffXfermode(PorterDuff.Mode.SRC_IN); /** * 設定當前矩形的高度為0 */ currentTop=bitmap.getHeight(); rectF=new RectF(0,currentTop,bitmap.getWidth(),bitmap.getHeight()); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(bitmap.getWidth(),bitmap.getHeight()); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); rectF.top=currentTop; /** * 設定View的離屏緩衝。在繪圖的時候新建一個“層”,所有的操作都在該層而不會影響該層以外的影象 * 必須設定,否則設定的PorterDuffXfermode會無效,具體原因不明 */ int sc=canvas.saveLayer(0,0,totalW,totalH,paint,Canvas.ALL_SAVE_FLAG); canvas.drawBitmap(bitmap,0,0,null); paint.setXfermode(xfermode); paint.setColor(Color.RED); canvas.drawRect(rectF,paint); paint.setXfermode(null); /** * 還原畫布,與canvas.saveLayer配套使用 */ canvas.restoreToCount(sc); if (currentTop>0){ currentTop--; postInvalidate(); } } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); totalW=w; totalH=h; } }
2、圓形圖片
程式碼如下:
public class CircleImageView extends View { private int resId; private Bitmap bitmap; private Paint paint; private int bitmapWidth,bitmapHeight; private int size; private PorterDuffXfermode xfermode; public CircleImageView(Context context, AttributeSet attrs) { super(context, attrs); TypedArray array=context.obtainStyledAttributes(attrs, R.styleable.CircleImageView); resId=array.getResourceId(R.styleable.CircleImageView_imageRes,R.mipmap.ic_launcher); array.recycle(); init(); } private void init(){ paint=new Paint(Paint.ANTI_ALIAS_FLAG); paint.setDither(true);//設定是否使用影象抖動處理,會使繪製出來的圖片顏色更加平滑和飽滿,影象更加清晰 paint.setFilterBitmap(true);//加快顯示速度,本設定項依賴於dither和xfermode的設定 bitmap= BitmapFactory.decodeResource(getResources(),resId); bitmapWidth=bitmap.getWidth(); bitmapHeight=bitmap.getHeight(); xfermode=new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP); size=Math.min(bitmapWidth,bitmapHeight); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(size,size); } /** * 生成圓形Bitmap * @return */ private Bitmap makeCircle(){ Bitmap bitmap=Bitmap.createBitmap(size,size, Bitmap.Config.ARGB_8888); Canvas canvas=new Canvas(bitmap); Paint paint=new Paint(Paint.ANTI_ALIAS_FLAG); paint.setColor(Color.BLUE); paint.setStyle(Paint.Style.FILL); int radius=size/2; canvas.drawCircle(size/2,size/2,radius,paint); return bitmap; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int sc=canvas.saveLayer(0,0,size,size,paint,Canvas.ALL_SAVE_FLAG); Bitmap dst=makeCircle(); canvas.drawBitmap(dst,0,0,paint); paint.setXfermode(xfermode); canvas.drawBitmap(bitmap,0,0,paint); paint.setXfermode(null); canvas.restoreToCount(sc); } }
對應屬性定義:
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="CircleImageView"> <attr name="imageRes" format="reference"/> </declare-styleable> </resources>
關於圓形圖片的詳細介紹可以看鴻洋大大的這篇博文,介紹的非常詳盡:
http://blog.csdn.net/lmj623565791/article/details/42094215
關於PorterDuffXfermode的應用還有非常多,這裡簡單介紹這幾個。
以上內容大部分參考自:
http://blog.csdn.net/tianjian4592/article/details/44783283
http://blog.csdn.net/aigestudio/article/details/41316141
http://www.cnblogs.com/tianzhijiexian/p/4297172.html
相關推薦
Android Paint Xfermode 學習小結
一、setXfermode(Xfermode xfermode) Xfermode國外有大神稱之為過渡模式,這種翻譯比較貼切但恐怕不易理解,大家也可以直接稱之為影象混合模式,因為所謂的“過渡”其實就是影象混合的一種,這個方法跟我們上面講到的setColorFilter蠻相似的。檢視API文件發現其果然有三個子
影象混合模式:Android Paint Xfermode 使用和demo
一、setXfermode(Xfermode xfermode) Xfermode國外有大神稱之為過渡模式,這種翻譯比較貼切但恐怕不易理解,大家也可以直接稱之為影象混合模式,因為所謂的“過渡”其實就是影象混合的一種,這個方法跟我們上面講到的setColorFilter蠻相似
Android 動畫學習小結
2.3以及以前的版本支援3種類型的動畫:逐幀動畫,佈局動畫,檢視動畫。佈局動畫,檢視動畫合稱為補間動畫。 3.0後推出了屬性動畫 一.逐幀動畫 逐幀動畫就像動畫片一樣把一些圖片組合並且快速播放,好像物體在運動一樣。 建立逐幀動畫,使用AnimationDrawable這個類
Android 開發學習小結(六)
一、Task基本概念與執行過程 場景:一個應用程式包含3個Activity,每個Activity介面一個按鈕。Activity1按鈕點選後跳轉到 Activity2,Activity2的按鈕點選後跳轉到Activity3,Activity3的按鈕點選後進行簡訊傳送。
Android 資源(resource)學習小結
Android 資源(resource)學習小結 運用Android SDK進行UI開發時,雖然也可以使用純程式碼來完成,但是那種方法對我這種剛學習Android對API還不懂的人來說,能進行類似VB、MFC一樣圖形化開發自然是最合適不過的。幸好Android也提供了這種方式,
Android 開發學習小結(五)
一、七個狀態對應的處理函式 // 當Activity第一次呼叫時,主要用於對介面控制元件進行layout佈局處理以及事件繫結; protected void onCreate(Bundle savedInstanceState); // 當Activity的介面能被使
Android 開發學習小結(七)
一、LinearLayout的使用方法 1.線性佈局:將控制元件一個挨著一個的從上到下排列; 2.Activity可配置樣式 android:orientation="vertical" -- 線性佈局樣式的方向(垂直或水平) 3.控制元件可設定樣式屬性 an
Android:Sqlitedatabase學習小結
今天剛剛學習完Sqlite資料庫的基礎知識,隨即把學到的東西記錄下來,以便隨後查閱,以下是自己對Sqlite資料庫的小結:1.Sqlite簡介 Sqlite是一款輕型的資料庫,它包含在一個相對小的C庫中,它的設計目標是嵌入式的,由於它佔用資源非常少,可能只需要
Android應用基礎學習記錄
應用 ctp 例如 case 推薦 都沒有 變量命名規則 bytearray href 01_前言 前言,了解了Android的情況。這裏也介紹一下本文。本文是記錄學習Android應用程序開發過程,視頻中使用的Android2.2版本號,我以4.2版本號為基礎,找
纏中說禪學習小結圖譜
提醒 模式 www 趨勢 包括 包含 表示 小結 一中 1,筆,頂分型+至少1根K線+底分型=筆,頂與底之間的其它波動可以忽略不計。但一定要是相鄰的頂與底! 2,線段,三筆為一線段:一個線段,除非是缺口,否則必須由至少上下上或下上下的三折所組成。 只要互相相鄰的上或下不
Android ViewPager使用方法小結
nco col tile 情況 谷歌 obj wpa sla 釋放 android-support-v4.jar 是谷歌提供給我們的一個兼容低版本安卓設備的軟件包,裏面包囊了只有在 Android 3.0 以上可用的API。而 ViewPager 就是其中之一。利用它,我們
React學習小結(二)
display lin body -a 頁面 return 有時 borde size 一、組件的嵌套 1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UT
React學習小結(三)
color render pro sed nbsp 合數 白雪 方式 內部 一、React數據的傳輸 1、屬性和狀態是react中數據傳遞的載體 2、屬性是聲明以後不允許被修改的東西 3、屬性只能在組件初始化的時候聲明並傳入組件內部,並且在組件內部通過this.props
OC學習小結之ios運行過程詳解
for cat 用戶 with res nbsp c學習 launch cati 1)ios核心類 UIView 視圖,屏幕上能看得見的東西都是視圖,例如:按鈕、文本標簽、和表格等 UIViewController:內部默認有個視圖(UIView),負責管理UIView的
python學習小結
www 技術 二維 學習 設計 格式 name 字符串 循環 1學習的課程名字叫什麽 python:前端初識html,後臺基礎flask 2怎麽輸出一句話,用代碼舉例 輸出用:print 例如: 3使用終端工具怎麽運行 Python代碼 例如我要運行題目2的程序,我的py文
Android PopupWindow使用方法小結
ring hub tps enter offset [] 註意 外部 現在 前幾天要用到PopupWindow,一時竟想不起來怎麽用,趕緊上網查了查,自己寫了個demo,並在此記錄一下PopupWindow的用法。 使用場景 PopupWindow,顧名思義,就是彈窗,在很
android monkey測試學習
發生 退出 adb 解決 ash 隨機 級別 監視 信息 前提是:有安卓環境,能用adb命令 一、Monkey 測試的目的? 該工具可用於測試穩定性。 開發人員結合monkey 打印的日誌 和系統打印的日誌,解決測試中出現的問題 二、Monkey 測試的特點?Monkey
aNDROID開發新手學習建議
aid 新手學 roi oid .com lis hao123 music android aNDROID%E9%87%8C%E9%9D%A2%E5%A6%82%E4%BD%95%E5%85%8B%E9%9A%86%E5%AF%B9%E8%B1%A1 http://musi
抽象類和接口學習小結
write 普通 繼承 調用 抽象方法 實例 add 一個 抽象 區別:1.本質區別是抽象類描述這個類是什麽,而接口則是描述這個類可以做什麽功能。2.接口的方法都是publice3.抽象類被繼承時,子類要實現父類所有抽象方法,要overwrite關鍵字4.抽象類可以包含字段
201671010130 2016-2017-2 《Java程序設計》第二周學習小結
博客 返回 由於 程序 使用 spa family 浮點 multi 學習Java第三章小結 本周我學會了: 首先是解決關於解決運行程序前出現了錯誤提示“editor dose not contain a main type”程序無法運行”的問題,通過網友的博客http: