Explication détaillée de la collection de méthodes de découpe de l'API Canvas (partie 2)


Introduction à cette section :

Cette section continue d'apporter une explication détaillée de la série de dessins Android - API Canvas (Partie 2). Famille de méthodes ClipXxx ! Nous pouvons voir qu'il existe trois types de méthodes Clip qui nous sont fournies dans le document : clipPath( ), clipRect( ), clipRegion( ); >

Grâce à différentes combinaisons de chemin, rect et région, presque toutes les formes de zone de recadrage peuvent être prises en charge !

Chemin : Il peut s'agir d'une courbe ouverte ou fermée, d'un ensemble complexe de lignes composées de graphiques

Rect : Zone rectangulaire

Région : Cela peut être compris comme une combinaison de régions. Par exemple, deux régions peuvent être ajoutées, soustraites, combinées, confondues, etc. !

Region.Op définit les types d'opérations inter-régions soutenues par Région ! Nous en reparlerons plus tard, Une autre chose à dire est que ce que nous entendons habituellement par découpage peut être le découpage de graphiques existants, mais sous Android, le découpage Le clip sur la toile doit être effectué avant de dessiner. Si vous clipsez sur la toile après le dessin, cela n'affectera pas. Accédez aux graphiques dessinés, rappelez-vous que Clip est destiné à Canvas, pas aux graphiques ! Bon, pas de BB, commençons directement cette section !

Document officiel de l'API : Canvas


1. Explication détaillée de la méthode de combinaison Region.Op

<🎜. >

En fait, la difficulté n'est rien de plus que cela. La région représente une région, qui représente une certaine zone fermée sur le calque Canvas ! Bien sûr, si vous avez le temps, vous pouvez déduire lentement cette classe par vous-même, et ce sur quoi nous nous concentrons habituellement n'est qu'une de ses valeurs d'énumération :
Op

Prenons un regardez chacun d'entre eux. Le rôle des valeurs d'énumération : On suppose deux zones de recadrage A et B, puis on appelle la valeur d'énumération correspondant à Region.Op : 1.png

DIFFÉRENCE

: la ensemble de différences plage de A et B, C'est-à-dire A - B, seul le contenu du dessin dans cette plage sera affiché

INTERSECT

 : c'est-à-dire la plage intersection de A et B, uniquement ; dans cette plage Uniquement le contenu du dessin dans

UNION

 : c'est-à-dire la plage union de A et B, c'est-à-dire le contenu du dessin de la plage incluse dans les deux seront affichés. ;

XOR

: la plage complémentaire de A et B. Dans cet exemple, c'est la plage de A sauf B. Seul le dessin le contenu dans cette plage sera affiché ;

REVERSE_DIFFERENCE

 : la plage ensemble de différences de B et A, c'est-à-dire B - A, uniquement le contenu du dessin à l'intérieur de cette plage. la plage sera affichée ;

REPLACE

 : Quel que soit l'état de collecte de A et B, la plage de B sera affichée entièrement. Si elle croise A, la plage d'intersection de A sera affichée. être couvert ; Si vous avez étudié des ensembles, alors il sera clair de dessiner un diagramme de Venn. Vous ne l'avez pas étudié ? C'est bon, essayons en écrivant un exemple Résultat correspondant~! Écrivez une méthode pour initialiser le pinceau et dessiner un rectangle :

private void init() {
    mPaint = new Paint();
    mPaint.setAntiAlias(true);
    mPaint.setStrokeWidth(6);
    mPaint.setColor(getResources().getColor(R.color.blush));
}

private void drawScene(Canvas canvas){
    canvas.drawRect(0, 0, 200, 200, mPaint);
}

Op.DIFFERENCE:

canvas.clipRect(10, 10, 110, 110);        //第一个
canvas.clipRect(50, 50, 150, 150, Region.Op.DIFFERENCE); //第二个
drawScene(canvas);

Résultat:

2.png

En utilisant (10,10) et (50,50) comme points de départ, deux rectangles de 100*100 ont été recadrés. Le résultat du recadrage est :

La différence entre A et B = A - (Le intersection de A et B)


Op.INTERSECT:

canvas.clipRect(10, 10, 110, 110);        //第一个
canvas.clipRect(50, 50, 150, 150, Region.Op.INTERSECT); //第二个
drawScene(canvas);

Résultat:

3.png

En utilisant (10,10) et (50,50) comme points de départ, deux rectangles de 100*100 ont été recadrés. Les résultats du recadrage sont : A et B L'intersection = L'intersection de A. et B


Op.UNION:

canvas.clipRect(10, 10, 110, 110);        //第一个
canvas.clipRect(40, 40, 140, 140, Region.Op.UNION); //第二个
drawScene(canvas);

Résultat:

4.png

En utilisant (10,10) et (50,50) comme points de départ, deux rectangles de 100*100 ont été recadrés. Les résultats du recadrage sont : A et B L'union de l'aire de A + B


Op >

Découpez deux rectangles de 100*100 à partir de (10,10) et (50,50) comme points de départ. le résultat est : A et le complément de B = l'ensemble de A et B - l'intersection de A et B

5.png

Op.REVERSE_DIFFERENCE :

canvas.clipRect(10, 10, 110, 110);        //第一个
canvas.clipRect(50, 50, 150, 150, Region.Op.XOR); //第二个
drawScene(canvas);


résultat

:

Découpez deux rectangles de 100*100 de (10,10) et (50,50) comme points de départ, et les résultats de recadrage sont obtenus C'est : La différence entre B et A = B - l'intersection de A et B

6.png

Op.REPLACE

canvas.clipRect(10, 10, 110, 110);        //第一个
canvas.clipRect(50, 50, 150, 150, Region.Op.REVERSE_DIFFERENCE); //第二个
drawScene(canvas);


Résultat

:

découpez deux rectangles de 100*100 de (10,10) et (50,50) comme points de départ, et le recadrage résultant Le résultat est : Quel que soit l'état défini de A et B, la plage de B sera entièrement affichée si elle croise A, la plage d'intersection de A sera couverte

<🎜 ; >

7.png2. Exemples d'utilisation de Region.Op :

Exemple de référence de : Apprentissage graphique 2D Android (2), Canvas Part 2, Canvas Clipping and Region, RegionIterator


Exécuter le rendu

 :

Code pièce clé MyView.java :

canvas.clipRect(10, 10, 110, 110);        //第一个
canvas.clipRect(50, 50, 150, 150, Region.Op.REPLACE); //第二个
drawScene(canvas);

8.gifAnalyse de la mise en œuvre

 :

Obtenez la largeur et la hauteur lors de l'initialisation, puis bouclez Vous pouvez comprendre que l'image est divisée en lignes. La condition de boucle est : i * la hauteur de chaque ligne. Pas plus grande que la hauteur, puis la ligne est divisée en deux situations. L'union des régions est appelée, ce qui est en fait la méthode de coupe d'UNINO. C'est tout. Enfin, nous jugeons si l'image est affichée à ce moment-là, gérons différemment les situations de masquage et d'affichage, et enfin appelons invalidate(). Redessinez! C'est assez simple, comprenez-le vous-même~

Autre point : la transformation Canvas n'a aucun effet sur clipRegion


3 Explication détaillée de la méthode clipRect :

< 🎜. >clipRect fournit sept méthodes surchargées :

9.png

Les paramètres sont introduits comme suit :

rect : Objet Rect, utilisé pour définir la plage de la zone de recadrage. Rect et RectF ont des fonctions similaires, mais la précision est différente des méthodes fournies.

gauche : La position gauche du. zone de recadrage rectangulaire

top : La position supérieure de la zone de recadrage rectangulaire

droite : La position droite de la zone de recadrage rectangulaire

bottom : La position inférieure de la zone de recadrage rectangulaire

op : La méthode de combinaison de la zone de recadrage

Les quatre valeurs ci-dessus ​​peut être une virgule flottante ou un entier

Exemple d'utilisation:

/**
 * Created by Jay on 2015/11/10 0010.
 */
public class MyView extends View{

    private Bitmap mBitmap = null;
    private int limitLength = 0;     //
    private int width;
    private int heigth;
    private static final int CLIP_HEIGHT = 50;

    private boolean status = HIDE;//显示还是隐藏的状态,最开始为HIDE
    private static final boolean SHOW = true;//显示图片
    private static final boolean HIDE = false;//隐藏图片

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

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.img_meizi);
        limitLength = width = mBitmap.getWidth();
        heigth = mBitmap.getHeight();
    }

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

    @Override
    protected void onDraw(Canvas canvas) {
        Region region = new Region();
        int i = 0;
        while (i * CLIP_HEIGHT <= heigth) {//计算clip的区域
            if (i % 2 == 0) {
                region.union(new Rect(0, i * CLIP_HEIGHT, limitLength, (i + 1) * CLIP_HEIGHT));
            } else {
                region.union(new Rect(width - limitLength, i * CLIP_HEIGHT, width, (i + 1)
                        * CLIP_HEIGHT));
            }
            i++;
        }
        canvas.clipRegion(region);
        canvas.drawBitmap(mBitmap, 0, 0, new Paint());
        if (status == HIDE) {//如果此时是隐藏
            limitLength -= 10;
            if(limitLength = width)
                status=HIDE;
        }
        invalidate();
    }
}

Exécuter le résultat:

10.png

D'après l'exemple ci-dessus, je ne sais pas. L'avez-vous découvert ? clipRect sera affecté par la transformation Canvas. La zone blanche est la zone non éclaboussée, donc clipRect recadre le canevas. Et notre dessin est réalisé sur cette toile recadrée ! Tout ce qui dépasse cette zone ne sera pas affiché !


4. Explication détaillée de la méthode clipPath :

11.png

Par rapport à clipRect, clipPath n'a que deux méthodes surchargées. La méthode d'utilisation est très simple. . Vous pouvez alors dessiner un Paht. Passez-le simplement !

Exemple d'utilisation :

Ici, nous réutilisons l'exemple circulaire ImageView que nous avons écrit auparavant dans ImageView~

Code d'implémentation:

ImageView personnalisée : RoundImageView.java

mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(Color.BLACK);
mPaint.setTextSize(60);

canvas.translate(300,300);
canvas.clipRect(100, 100, 300, 300);                //设置显示范围
canvas.drawColor(Color.WHITE);                      //白色背景
canvas.drawText("双11,继续吃我的狗粮...", 150, 300, mPaint); //绘制字符串

Code de mise en page :

activity_main.xml:

/**
 * Created by coder-pig on 2015/7/18 0018.
 */
public class RoundImageView extends ImageView {

    private Bitmap mBitmap;
    private Rect mRect = new Rect();
    private PaintFlagsDrawFilter pdf = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG);
    private Paint mPaint = new Paint();
    private Path mPath=new Path();
    public RoundImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }


    //传入一个Bitmap对象
    public void setBitmap(Bitmap bitmap) {
        this.mBitmap = bitmap;
    }


    private void init() {
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
        mPaint.setAntiAlias(true);// 抗锯尺
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if(mBitmap == null)
        {
            return;
        }
        mRect.set(0,0,getWidth(),getHeight());
        canvas.save();
        canvas.setDrawFilter(pdf);
        mPath.addCircle(getWidth() / 2, getWidth() / 2, getHeight() / 2, Path.Direction.CCW);
        canvas.clipPath(mPath, Region.Op.REPLACE);
        canvas.drawBitmap(mBitmap, null, mRect, mPaint);
        canvas.restore();
    }
}

MainActivity.java:

<com.jay.demo.imageviewdemo.RoundImageView
        android:id="@+id/img_round"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_margin="5px"/>

Rendu en cours d'exécution :

12.png

De plus, l'ImageView arrondi réalisé à l'aide de cette méthode aura des bords irréguliers évidents, même si vous définissez pour Peinture, Toile L'anti-aliasing est inutile ~ Si vous avez des exigences élevées, vous pouvez utiliser Xfermode-PorterDuff pour définir le brassage des images afin d'y parvenir. Fondamentalement, pas d'alias, vous pouvez voir :

Tutoriel d'introduction de base Android - 8.3.6 API Paint - Explication détaillée de Xfermode et PorterDuff (3)


5. Téléchargez l'exemple de code dans cette section :

CanvasDemo2.zip

XfermodeDemo1.zip


Résumé de cette section :

Bon, cette section va vous expliquer les trois méthodes de découpe dans Canvas : clipPath(), clipRect(), clipRegion(), la difficulté devrait être dans la dernière. Il existe six combinaisons d'opérations différentes. En fait, ce n'est pas difficile. C'est juste un concept, mettez-le simplement au début et digérez-le, mais clipPath() et clipRect() ne sont pas difficiles~ Oui, c'est Double 11 aujourd'hui, je me demande si vous avez acheté vos mains~13.jpg