Canvas APIの詳細解説(その2)カットメソッド集


このセクションの紹介:

このセクションでは引き続き Android 描画シリーズ - Canvas API (パート 2) について詳しく説明します。 ClipXxx メソッドファミリーが登場!このドキュメントでは、clipPath( )、clipRect( )、clipRegion( ) の 3 種類の Clip メソッドが提供されていることがわかります。Path、Rect、Region のさまざまな組み合わせによって、ほぼ任意の形状のトリミングエリア!

Path

: 開いた曲線または閉じた曲線、または複雑な線の集合です。

Rect

: 長方形の領域

Region

: たとえば、2 つの領域の組み合わせとして理解できます。領域は、減算、結合、疑いなどを加算することができます。 Region.Op は、Region でサポートされるリージョン間操作のタイプを定義します。それについては後で話しますが、 もう 1 つ言えるのは、私たちが通常クリッピングとして理解しているのは、既存のグラフィックをクリップすることかもしれませんが、Android ではクリッピングは Clip on Canvas は描画前に行う必要があります。描画後に Clip on Canvas を行っても影響はありません。 描画されたグラフィックスに移動します。クリップはグラフィックスではなくキャンバス用であることに注意してください。 さて、BB はありません。このセクションを直接始めましょう!

公式APIドキュメント

: Canvas1.Region.Op結合メソッドの詳細説明


実際、難しいのはRegionは領域を表し、それは上の特定の閉じた領域を表します。キャンバスレイヤーです! もちろん、時間があれば、このクラスを自分でゆっくりと差し引くこともできます。通常、注目するのはその列挙値の 1 つだけです:

Op

各列挙値の役割を見てみましょう: 2 つのトリミング領域 A と B を想定し、Region.Op に対応する列挙値を呼び出します:

1.png

DIFFERENCE

: A と B の

差集合 範囲、つまり A - B、この範囲内のみを描画しますコンテンツが表示されます。 INTERSECT

: つまり、A と B の

intersection の範囲が表示されます。 UNION

: つまり、

union の範囲が表示されます。 A と B の、つまり両方に含まれる範囲の描画内容が表示されます XOR

: A と B の

補数範囲、この例では、B を除く A の範囲のみが表示されます。この範囲内の描画コンテンツが表示されます。 REVERSE_DIFFERENCE

: B と A の

差分セット の範囲、つまり B - A、この範囲内の描画コンテンツのみが表示されます REPLACE

: AとBに関係なく、Bの範囲全体が表示されます。Aと交差する場合は、Aの交差範囲がカバーされます

セットを学習している場合は、 Venn (ベン図) を学習していない場合は?よし、サンプルを書いてやってみよう 相応の結果〜!ブラシを初期化して四角形を描画するメソッドを作成します:

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);

Result:

2.png

開始点として 100*100 の 2 つの長方形を (10,10) と (50,50) で切り取ると、次の結果が得られます。トリミング結果は次のとおりです:

A と B の差集合 = A - (A と B の交差)


Op.INTERSECT:

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

Result:

3.png

( 10 ,10) と (50,50) が開始点として使用され、2 つの 100*100 の長方形が切り取られます。切り抜き結果は次のようになります。 A と B の交差 = A と B の交差


Op. UNION:

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

Result:

4.png

開始点として (10,10) と (50,50) から 2 つの 100*100 の長方形を切り取り、トリミング結果は次のようになります:A B の和集合= A の面積 + B の面積


Op.、100*100 の 2 つの長方形がトリミングされ、トリミング結果は次のようになります: A と B の補数 = A と B のセット - AとBの交差点

Op.REVERSE_DIFFERENCE

:5.png

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

Result:


(10,10)と(50,50)を始点として100*100の長方形を2つ切り出すトリミング結果は次のとおりです: B と A の差集合 = B - A と B の交差

Op.REPLACE

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

Result

:


started at (10,10) (50,50) と 2 つの 100*100 の長方形を切り取った場合、切り抜き結果は次のようになります。 A と B の設定状況に関係なく、B の範囲が A と交差する場合、その交差範囲がすべて表示されます。 A について説明します。

2.Region の使用例:

サンプル参照:

Android 2D グラフィックス学習 (2)、Canvas Part 2、Canvas Cropping and Regional、RegionIterator7.png

Running Effect Picture :


主要部分コード MyView.java :

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

実装分析:

初期化中に幅と高さを取得し、ループします。画像が行に分割されていることがわかります。ループ条件は、i * 各行の高さです。 高さ以下の場合、線は 2 つの状況に分割されます。これは、実際には UNINO の切断方法です。 最後に、この時点で画像が表示されるかどうかを判断し、非表示と表示の状況を別の方法で処理し、最後に validate() を呼び出します。 描き直し!非常に簡単ですので、ご自身で理解してください~

もう一つのポイント: Canvas の変換は、clipRegion には影響しません


3。

rect9.png: Rect オブジェクト。トリミング領域の範囲を定義するために使用されます。Rect と RectF は同様の機能を持ちますが、提供されているメソッドとは精度が異なります

left: 左長方形のトリミング領域の位置

top: 長方形のトリミング領域の上の位置

right: 長方形のトリミング領域の右の位置

bottom: 長方形のトリミング領域の下の位置

op: トリミング領域の組み合わせ

上記4つのA値は浮動小数点型でも整数型でも可能です

使用例

:

/**
 * 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();
    }
}

実行結果

:

上記よりたとえば、見つけましたか? ClipRect は Canvas 変換の影響を受けるため、白い領域は花のない領域であるため、clipRect はキャンバスをトリミングします。 そして、私たちの描画はこの切り取られたキャンバス上で行われます。この領域を超えるものは表示されません。

4. ClipPath メソッドの詳細な説明:

10.png

ClipRect と比較して、ClipPath には 2 つのオーバーロードされたメソッドしかありません。使用方法は非常に簡単です。 ただ渡してください! usageの例:semage view〜


explementationコードで以前に書いた円形の画像の例を再利用します
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); //绘制字符串

MainActivity.java

:11.png

/**
 * 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();
    }
}

Running renderings

:

さらに、このメソッドを使用して作成された丸みを帯びた ImageView は、ペイントとキャンバスに設定した場合でも、明らかなギザギザのエッジを持ちます。 アンチエイリアシングは役に立ちません~ 高い要件がある場合は、Xfermode-PorterDuff を使用して画像シャッフルを設定してそれを実現できます。 基本的にエイリアシングはありません。以下を参照してください:

Android の基本的な入門チュートリアル - 8.3.6 Paint API - Xfermode と PorterDuff の詳細な説明 (3)


5. このセクションのサンプル コードをダウンロードします:

CanvasDemo2.zip

XfermodeDemo1.zip


このセクションの概要:

このセクションでは、Canvas でカットする方法を説明します。 3 つのメソッド:clipPath()、clipRect()、 ClipRegion() は、最後の 1 つにあります。実際には、6 つの異なる Op コレクションがあります。 単なる概念なので、最初に置くだけで簡単に理解できますが、clipPath()とclipRect()は難しくありません〜 はい、今日はダブル11です、やったかな〜13.jpg