Introduction de la section :
Dans la section précédente, nous avons découvert les deux fils de Xfermode qui sont déjà passés de vie à trépas (devenus obsolètes) :AvoidXfermode, PixelXorXfermode, bien qu'ils soient quelque peu utiles, ils sont finalement obsolètes. Dans cette section, découvrons le troisième fils de Xfermode, qui est toujours en vie :PorterDuffXfermode;
Tout d'abord, présentons la documentation officielle de l'API :PorterDuffXfermode! Le contenu de la documentation est très limité ; on peut voir son constructeur :
Il n'y a qu'un seul paramètre :PorterDuff.Modemode, et Android nous fournit 16 modes de fusion d'images. En termes simples, deux calques peuvent être combinés selon différents modes pour produire des résultats différents ! Les schémas de résultat des 16 modes de fusion sont les suivants :
Voici les deux calques : l'image dessinée en premier estimage de destination (DST), et l'image dessinée ensuite estimage source (SRC)!
Bien sûr, dans la documentation, nous constatons que les modes disponibles ne sont pas 16 mais 18, avec l'ajout deADDetOVERLAYdeux modes !
Bon, parler davantage ne sert à rien ; le code est ce qu'il y a de plus pratique. Dans cette section, écrivons du code pour vérifier ces 18 modes !
PS : Le nom PorterDuff est en réalité une combinaison des noms de deux personnes : Tomas Proter et Tom Duff. Ce sont les grands maîtres qui ont les premiers proposé le concept de fusion graphique à SIGGRAPH. Si vous êtes intéressé, cherchez vous-même sur Baidu~
Écrivons un exemple pour vérifier le diagramme ci-dessus :
Très bien, écrivons un exemple pour vérifier le diagramme ci-dessus, et comparons et analysons les résultats en basculant entre différents modes !
Implémentation du code:
Étape 1: D'abord, écrivons une classe utilitaire pour obtenir la largeur et la hauteur de l'écran !ScreenUtil.java:
/**
* Created by Jay on 2015/10/23 0023.
*/
public class ScreenUtil {
/**
* 获取屏幕宽高,sdk17后不建议采用
*
* @param context
*/
public static int[] getScreenHW(Context context) {
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = manager.getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
int[] HW = new int[] { width, height };
return HW;
}
/**
* 获取屏幕宽高,建议采用
*
* @param context
*/
public static int[] getScreenHW2(Context context) {
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm = new DisplayMetrics();
manager.getDefaultDisplay().getMetrics(dm);
int width = dm.widthPixels;
int height = dm.heightPixels;
int[] HW = new int[] { width, height };
return HW;
}
/**
* 获取屏幕的宽度
*
* @param context
* @return
*/
public static int getScreenW(Context context) {
return getScreenHW2(context)[0];
}
/**
* 获取屏幕的高度
*
* @param context
* @return
*/
public static int getScreenH(Context context) {
return getScreenHW2(context)[1];
}
}
Étape 2 : Écrivons notre classe View personnalisée et faisons des expériences ici !XfermodeView.java:
/**
* Created by Jay on 2015/10/23 0023.
*/
public class XfermodeView extends View {
private PorterDuffXfermode pdXfermode; //定义PorterDuffXfermode变量
//定义MODE常量,等下直接改这里即可进行测试
private static PorterDuff.Mode PD_MODE = PorterDuff.Mode.ADD;
private int screenW, screenH; //屏幕宽高
private int width = 200; //绘制的图片宽高
private int height = 200;
private Bitmap srcBitmap, dstBitmap; //上层SRC的Bitmap和下层Dst的Bitmap
public XfermodeView(Context context) {
this(context, null);
}
public XfermodeView(Context context, AttributeSet attrs) {
super(context, attrs);
screenW = ScreenUtil.getScreenW(context);
screenH = ScreenUtil.getScreenH(context);
//创建一个PorterDuffXfermode对象
pdXfermode = new PorterDuffXfermode(PD_MODE);
//实例化两个Bitmap
srcBitmap = makeSrc(width, height);
dstBitmap = makeDst(width, height);
}
public XfermodeView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
//定义一个绘制圆形Bitmap的方法
private 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(0xFF26AAD1);
c.drawOval(new RectF(0, 0, w * 3 / 4, h * 3 / 4), p);
return bm;
}
//定义一个绘制矩形的Bitmap的方法
private 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(0xFFFFCE43);
c.drawRect(w / 3, h / 3, w * 19 / 20, h * 19 / 20, p);
return bm;
}
@Override
protected void onDraw(Canvas canvas) {
Paint paint = new Paint();
paint.setFilterBitmap(false);
paint.setStyle(Paint.Style.FILL);
canvas.drawBitmap(srcBitmap, (screenW / 3 - width) / 2, (screenH / 2 - height) / 2, paint);
canvas.drawBitmap(dstBitmap, (screenW / 3 - width) / 2 + screenW / 3, (screenH / 2 - height) / 2, paint);
//创建一个图层,在图层上演示图形混合后的效果
int sc = canvas.saveLayer(0, 0, screenW, screenH, 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.drawBitmap(dstBitmap, (screenW / 3 - width) / 2 + screenW / 3 * 2,
(screenH / 2 - height) / 2, paint); //绘制i
//设置Paint的Xfermode
paint.setXfermode(pdXfermode);
canvas.drawBitmap(srcBitmap, (screenW / 3 - width) / 2 + screenW / 3 * 2,
(screenH / 2 - height) / 2, paint);
paint.setXfermode(null);
// 还原画布
canvas.restoreToCount(sc);
}
}
Le code semble compliqué, n'est-ce pas ? En fait, il ne l'est pas. Il récupère simplement la largeur et la hauteur de l'écran, puis dessine un rectangle et un cercle, calcule leurs positions, définit le calque (un motif fixe), puis définit le setXfermode du paint, et dessine ensuite sur le canvas. Ce que vous pourriez ne pas comprendre, c'est le calcul des positions de dessin, mais ce n'est pas le cas - vous pouvez définir les positions comme vous le souhaitez ! Ensuite, vérifions les résultats un par un. Vous avez juste besoin de changerPD_MODEla valeur pour différents modes !
Captures d'écran de l'effet en cours d'exécution:
1)PorterDuff.Mode.ADD:
Superposition de saturation
2)PorterDuff.Mode.CLEAR:
Le contenu dessiné ne sera pas appliqué au canevas. Eh bien, le résultat... Je ne sais pas pourquoi, normalement il n'y a rien...
3)PorterDuff.Mode.DARKEN:
Prenez toute la zone des deux calques et assombrissez la couleur de la partie d'intersection
4)PorterDuff.Mode.DST:
Seuls l'alpha et la couleur de l'image cible sont conservés, donc seule l'image cible est dessinée
5)PorterDuff.Mode.DST_ATOP:
Dessinez l'image cible là où les images source et cible se croisent, et dessinez l'image source là où elles ne se croisent pas
6)PorterDuff.Mode.DST_IN:
Dessiner l'image cible là où les deux se croisent, et l'effet de dessin est affecté par la transparence de l'image d'origine
7)PorterDuff.Mode.DST_OUT:
Dessiner l'image cible là où elles ne se croisent pas
8)PorterDuff.Mode.DST_OVER:
L'image cible est dessinée par-dessus
9)PorterDuff.Mode.LIGHTEN:
Prendre toute la zone des deux calques et éclaircir la couleur de la partie d'intersection
10)PorterDuff.Mode.MULTIPLY:
Prendre la couleur superposée de la partie d'intersection des deux calques
11)PorterDuff.Mode.OVERLAY:
Incrustation
12)PorterDuff.Mode.SCREEN:
Prendre toute la surface des deux calques, et la partie d'intersection devient transparente
13)PorterDuff.Mode.SRC:
Seuls l'alpha et la couleur de l'image source sont conservés, donc seule l'image source est dessinée
14)PorterDuff.Mode.SRC_ATOP:
Dessiner l'image source là où les images source et cible se croisent, et dessiner l'image cible là où elles ne se croisent pas
15)PorterDuff.Mode.SRC_IN:
Dessiner l'image source là où les deux se croisent
16)PorterDuff.Mode.SRC_OUT:
Dessiner l'image source là où elles ne se croisent pas
17)PorterDuff.Mode.SRC_OVER:
Dessiner l'image source au-dessus
18)PorterDuff.Mode.XOR:
Là où elles ne se croisent pas, dessinez les images source et cible telles quelles
Téléchargez le code d'exemple pour cette section :
PorterDuffXfermodeDemo.zip
Résumé de la section :
Eh bien, dans cette section, nous venons d'écrire une simple View pour vérifier les différents effets avec ces 18 valeurs différentes de PorterDuff.Mode. Hé hé, cela a pris pas mal de temps, mais cela doit être beaucoup plus clair pour les lecteurs, non ? Bien sûr, ce ne sont que quelques aperçus préliminaires !
PorterDuffXfermodedePorterDuff.ModeC'est très important pour nos contrôles personnalisés ! Dans cette section, nous en avons eu un aperçu préliminaire. Dans la section suivante, choisissons quelques exemples pour nous entraîner !
Si vous voulez voir une introduction plus détaillée à PorterDuff.Mode, consultez :Android Paint : Explication de setXfermode PorterDuffXfermode, un article bien écrit par quelqu'un d'autre ! Bon, c'est tout pour le moment. J'ai un bilan de santé demain matin, donc c'est tout ce que j'ai écrit aujourd'hui~



