API Paint - Explication détaillée de Xfermode et PorterDuff (2)


Introduction à cette section :

Dans la section précédente, nous avons entendu parler des deux fils décédés (obsolètes) de Xfermode : AvoidXfermode, PixelXorXfermode , Bien qu'il soit quelque peu utile, il a finalement été éliminé. Dans cette section, nous découvrirons le troisième fils de Xfermode qui est toujours en vie : PorterDuffXfermode

Tout d'abord, jetons un coup d'œil à le document officiel de l'API : PorterDuffXfermode  ! Le document contient très peu de contenu. On peut voir sa méthode de construction :

1.png

Il n'y a qu'un seul paramètre : le mode PorterDuff.Mode, et Android nous propose 16 modes de mixage d'images. , ça peut être plus simple Il est entendu que deux couches peuvent être combinées en résultats différents et affichées selon des modes différents ! Les images résultantes des 16 modes de mixage sont les suivantes :

2.png

Il y a deux calques ici : l'image dessinée en premier est l' image cible (DST) , et l'image dessinée plus tard est Image source (SRC) !

Bien sûr, dans le document nous avons constaté que les modes disponibles ne sont pas 16, mais 18, avec deux nouveaux modes : AJOUTER et OVERLAY

< ! 🎜>Eh bien, inutile d'en dire trop. Le code est le plus pratique. Dans cette section, nous écrivons le code pour vérifier ces 18 modes !

3.gif

PS : Le nom PorterDuff est en fait une combinaison de deux noms : Tomas Proter et Tom Duff, qui furent les premiers à La personne de niveau divin qui a proposé pour la première fois le concept de mixage graphique sur SIGGRAPH Si vous êtes intéressé, s'il vous plaît Baidu~


Écrivez un exemple pour vérifier l'image ci-dessus :

<🎜. >

D'accord, écrivons un exemple pour vérifier l'image ci-dessus, et comparons et analysons les résultats en modifiant différents modes !

Implémentation du code

 :

Étape 1

 : Écrivons d'abord une classe d'outils 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 : Écrivez notre classe View personnalisée et expérimentez 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é, mais ce n'est pas le cas. Il obtient simplement la largeur et la hauteur de l'écran, puis dessine un rectangle et un cercle. Calculez leurs positions, puis définissez le calque inférieur (méthode d'écriture fixe), puis définissez le pinceau inférieur setXfermode, puis C'est juste dessiné sur la toile. Ce que vous ne comprenez peut-être pas, c'est le calcul de la position du dessin. En fait, ce n'est pas le cas. Comment décider de la position ? Tout ira bien ! Voyons donc les résultats un par un. Il vous suffit de modifier la valeur de

PD_MODE

pour le mettre dans un mode différent !

Rendu des opérations

 :

1) PorterDuff.Mode.ADD :

4.pngSuperposition de saturation

2) PorterDuff.Mode.CLEAR :

5.png dessiné ne le soumettra pas à la toile, et le résultat... Je ne sais pas pourquoi, normalement il n'y a rien..

3) PorterDuff.Mode.DARKEN :

6.pngPrendre deux couches Tout zones, la partie d'intersection est de couleur plus foncée

4) PorterDuff.Mode.DST :

7.pngConserve uniquement l'alpha et la couleur de l'image cible, donc seule l'image cible est dessinée

5) PorterDuff.Mode.DST_ATOP :

8.pngL'image cible est dessinée là où l'image source et l'image cible se croisent, et l'image source est dessinée là où elles ne se croisent pas

6) PorterDuff.Mode.DST_IN :

9.pngL'image cible est dessinée à l'endroit où les deux se croisent, et l'effet de dessin sera affecté par la transparence de l'image originale

7) PorterDuff.Mode.DST_OUT :

10.pngDessinez le graphique cible à des endroits disjoints

8) PorterDuff.Mode.DST_OVER :

11.pngLe le graphique cible est dessiné ci-dessus

9) PorterDuff.Mode LIGHTEN :

12.pngPrenez toutes les zones des deux calques et éclairez la couleur de l'intersection

10) PorterDuff. .Mode.MULTIPLY :

13.pngPrendre les deux calques La couleur de la partie d'intersection après superposition est

11) PorterDuff.Mode.OVERLAY :

14.png Superposition

12) PorterDuff.Mode.SCREEN :

15.pngPrenez toutes les zones des deux calques, et la partie d'intersection devient transparente

13) PorterDuff.Mode .SRC :

16.pngConservez uniquement l'alpha et la couleur de l'image source, donc dessinez-la Uniquement l'image source

14) PorterDuff.Mode.SRC_ATOP :

000.pngL'image source est dessinée là où l'image source et l'image cible se croisent, et l'image cible est dessinée là où elles ne se croisent pas

15) PorterDuff.Mode.SRC_IN :

17.pngDessinez l'image source à l'endroit où les deux se croisent

16) PorterDuff.Mode.SRC_OUT :

18.png Dessinez l'image source là où elles ne se croisent pas

17) PorterDuff.Mode.SRC_OVER :

19.pngDessinez l'image source ci-dessus

18) PorterDuff.Mode.XOR :

20.pngLes images source et cible sont dessinées telles quelles là où elles ne se croisent pas


Téléchargez l'exemple de code pour cette section :

PorterDuffXfermodeDemo.zip


Résumé de cette section :

Eh bien, dans cette section, j'ai écrit une vue simple pour vérifier les différents effets de ces 18 PorterDuff différents .Mode. Hé, cela prend beaucoup de temps, mais cela semble définitivement beaucoup plus clair aux lecteurs, n'est-ce pas ~ Bien sûr, ce ne sont que quelques aperçus préliminaires ! Le

PorterDuff.Mode

de PorterDuffXfermode est très important pour nos contrôles personnalisés ! Dans cette section, nous avons une compréhension préliminaire. Dans la section suivante, nous choisirons quelques exemples à mettre en pratique !

Si vous souhaitez voir une introduction plus détaillée sur PorterDuff.Mode, veuillez consulter : Explication setXfermode PorterDuffXfermode d'Android Paint, un bon article écrit par d'autres ! Bon, ça y est, j'aurai un examen physique demain matin, c'est tout ce que j'écrirai aujourd'hui~21.jpg