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


Introduction à cette section :

Dans la section précédente, nous avons parlé du premier exemple d'utilisation de Xfermode et PorterDuff : l'implémentation de l'image arrondie et circulaire ImageView, Nous avons réalisé les avantages que PorterDuff.Mode.DST_IN nous a apportés. Dans cette section, nous continuerons à écrire des exemples pour mettre en pratique. Vous souvenez-vous encore de la mise en œuvre consistant à retirer les vêtements d’une belle fille que 8.3.2 Exemple pratique de dessin vous a apporté ?

1.gif

Notre plan de mise en œuvre à l'époque était de définir 20*20 pixels près de la zone tactile pour qu'elle soit transparente. Le rendu est comme ceci :

2.gif

Je ne le fais pas. sais Avez-vous remarqué un problème ? Quand on essuie les vêtements des belles femmes, ils sont tous carrés, mais quand on dessine la planche à dessin Lorsque nous dessinons une image, les lignes sont très douces. Existe-t-il un moyen de combiner les deux pour que lorsque nous essuyons les vêtements, ils soient également lisses ? La réponse est définitivement oui, utilisez simplement Xfermode ! Dans cette section, nous utilisons un autre mode, le mode DST_OUT ! Dessinez des graphiques cibles dans des endroits disjoints

3.png

Si vous oubliez un certain mode ou si vous n'avez même pas vu les 18 modes, veuillez passer à :Tutoriel d'introduction de base Android - 8.3 .5 API Paint - Explication détaillée de Xfermode et PorterDuff (2) De plus, je souhaite toujours poster le rendu de PorterDuff.Mode :

4.png

Eh bien, sans plus tarder, commençons cette section approximativement 🎜>.


Hmm, je ne sais pas combien de fois tu as vu ce Gif ? Je ne sais pas si la photo convient à tous les goûts, Xiaozhu Il a été extrait de l'application de quelqu'un d'autre. Ne me demandez pas mon numéro de téléphone ou mon adresse e-mail. Je ne sais rien, je cherche quelque chose. Demandez au chauffeur vétéran du groupe - Ji Shen, d'accord, analysons le processus de mise en œuvre ~

  • Parlons du principe. Il s'agit en fait de deux Bitmaps, un devant et un derrière. Celui de devant est habillé, et celui de derrière est nu. Utilisez ensuite un chemin pour enregistrer les graphiques dessinés par l'utilisateur, puis définissez le mode DST_OUT pour notre pinceau, puis Le DST (image cible) de la partie superposée avec Path, qui est l'image portant des vêtements, deviendra transparent ! D'accord, c'est facile ! Affinons-le lentement !
  • Nous avons d'abord besoin de deux Bitmaps pour stocker les images recto et verso. Ici, nous réalisons les deux Bitmaps en plein écran !
  • Ensuite, définissez le pinceau, les coins arrondis, la largeur du stylo, l'anticrénelage, etc. !
  • Définissez ensuite un chemin de dessin, qui est la méthode permettant à l'utilisateur de dessiner la zone. Dessinez simplement la zone après avoir défini Xfermode !
  • Ensuite, réécrivez la méthode onTouchEvent. Cette partie est la même que la planche à dessin personnalisée précédente !
  • Enfin, réécrivez la méthode onDraw(), dessinez d'abord l'image d'arrière-plan, appelez la méthode de l'utilisateur pour dessiner la zone, puis dessinez l'image de premier plan !

Cela peut paraître un peu compliqué, mais ce n'est pas le cas. Le code est super simple~


2. Une seule vue personnalisée——

StripMeiZi.java

/**
 * Created by Jay on 2015/10/25 0025.
 */
public class StripMeiZi extends View{

    private Paint mPaint = new Paint();
    private Path mPath = new Path();
    private Canvas mCanvas;
    private Bitmap mBeforeBitmap;
    private Bitmap mBackBitmap;
    private int mLastX,mLastY;
    private int screenW, screenH; //屏幕宽高
    private Xfermode mXfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);


    public StripMeiZi(Context context) {
        this(context, null);
    }

    public StripMeiZi(Context context, AttributeSet attrs) {
        super(context, attrs);
        screenW = ScreenUtil.getScreenW(context);
        screenH = ScreenUtil.getScreenH(context);
        init();
    }


    public StripMeiZi(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    private void init() {
        //背后图片,这里让它全屏
        mBackBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.meizi_back);
        mBackBitmap = Bitmap.createScaledBitmap(mBackBitmap, screenW, screenH, false);
        //前面的图片,并绘制到Canvas上
        mBeforeBitmap = Bitmap.createBitmap(screenW, screenH, Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mBeforeBitmap);
        mCanvas.drawBitmap(BitmapFactory.decodeResource(getResources(),
                R.mipmap.meizi_before), null, new RectF(0, 0, screenW, screenH), null);
        //画笔相关的设置
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND); // 圆角
        mPaint.setStrokeCap(Paint.Cap.ROUND); // 圆角
        mPaint.setStrokeWidth(80);    // 设置画笔宽
    }

    private void drawPath() {
        mPaint.setXfermode(mXfermode);
        mCanvas.drawPath(mPath, mPaint);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawBitmap(mBackBitmap, 0, 0, null);
        drawPath();
        canvas.drawBitmap(mBeforeBitmap, 0, 0, null);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (action)
        {
            case MotionEvent.ACTION_DOWN:
                mLastX = x;
                mLastY = y;
                mPath.moveTo(mLastX, mLastY);
                break;
            case MotionEvent.ACTION_MOVE:

                int dx = Math.abs(x - mLastX);
                int dy = Math.abs(y - mLastY);

                if (dx > 3 || dy > 3)
                    mPath.lineTo(x, y);

                mLastX = x;
                mLastY = y;
                break;
        }
        invalidate();
        return true;
    }
}
Code de mise en page

activity_main.xml

:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.jay.xfermodedemo2.StripMeiZi
        android:layout_width="match_parent"
        android:layout_height="match_parent"/></RelativeLayout>

3.

Exemple pratique - Démo d'arrachage des vêtements d'une belle femme, par rapport à ce que nous avons fait auparavant La façon d'arracher les vêtements d'une belle femme (en rendant transparents les 20*20 pixels près du point de contact) est beaucoup plus gracieuse ~ le code est également beaucoup plus simple, n'est-ce pas ? Réalisez les avantages que nous apporte le brassage d'images Android Xfermode, ou l'importance des contrôles personnalisés ! Eh bien, qu'est-ce que tu attends ? Ouvrez votre IDE, jouez avec le code et goûtez au plaisir d'arracher de beaux vêtements de femme~