Explicação detalhada da API Canvas do Android (parte 2) Coleção de métodos de corte

Introdução a esta seção:

Esta seção continua trazendo a Explicação Detalhada da API do Canvas (Parte 2) da Explicação Detalhada da Série de Desenhos do Android. Hoje vamos explicar a família de métodos ClipXxx no Canvas! Podemos ver que existem três tipos de métodos Clip fornecidos a nós no documento:  clipPath ( ), clipRect ( ), clipRegion ( );

Por meio de diferentes combinações de Path, Rect e Region, quase qualquer forma de área de recorte pode ser suportada!

Caminho : Pode ser uma curva aberta ou fechada, um conjunto complexo de gráficos compostos por linhas

Ret : área retangular

Região : Pode ser entendida como uma combinação de regiões, por exemplo, duas regiões podem ser somadas, subtraídas e confundidas!

Region.Op define os tipos de operações inter-regionais suportadas por Region! Falaremos sobre isso mais tarde, e outra coisa a dizer, o recorte que normalmente entendemos pode ser para recortar os gráficos existentes, mas no Android, o recorte do Canvas deve ser feito antes de desenhar a imagem. Se o Canvas for desenhado após o desenho Se você executar o Clip, isso não afetará os gráficos já desenhados. Lembre-se de que o Clip é para a Tela, não para os gráficos! Bem, não BB, apenas comece esta seção!

Documentação oficial da API : Canvas


1. Explicação detalhada do método de combinação Region.Op

Na verdade, a dificuldade nada mais é do que essa: Region representa uma região, ou seja, uma determinada área fechada na camada Canvas! Claro, quando você tiver tempo, você pode deduzir lentamente essa classe sozinho, e geralmente prestamos atenção apenas a um de seus valores de enumeração: Op

Vamos dar uma olhada no papel de cada valor de enumeração: Assumimos duas regiões de recorte A e B, então chamamos o valor de enumeração correspondente a Region.Op:

DIFERENÇA : A faixa de diferença de A e B , ou seja, A - B, será exibido apenas o conteúdo do desenho dentro desta faixa;

INTERSECT : Ou seja, o intervalo de interseção de A e B , apenas o conteúdo do desenho dentro deste intervalo será exibido

UNION : Ou seja, será exibido o intervalo de união de A e B , ou seja, será exibido o conteúdo do desenho do intervalo compreendido por ambos;

XOR : O intervalo de complemento de A e B , neste exemplo, o intervalo de A exceto B, apenas o conteúdo do desenho dentro deste intervalo será exibido;

REVERSE_DIFFERENCE : O intervalo da diferença entre B e A , ou seja, B - A, será exibido apenas o conteúdo do desenho dentro deste intervalo;

SUBSTITUIR : Independente do estado de coleta de A e B, a faixa de B será exibida em sua totalidade.Caso haja uma interseção com A, a faixa de interseção de A será percorrida;

Se você aprendeu coleções, então desenhar um Venn (diagrama de Venn) ficará claro, você não aprendeu? Tudo bem, vamos escrever um exemplo para tentar o resultado correspondente~! Escreva um método para inicializar o pincel e desenhar um retângulo:

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

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

Op.DIFERENÇA

canvas.clipRect(10, 10, 110, 110); //o primeiro 
canvas.clipRect(50, 50, 150, 150, Region.Op.DIFFERENCE); //o segundo 
drawScene(canvas);

resultado :

Começando em (10,10) e (50,50) sucessivamente, dois retângulos de 100*100 foram cortados e o resultado do corte é:

A diferença de A e B = A - (a interseção de A e B)


Op.INTERSECT

canvas.clipRect(10, 10, 110, 110); //o primeiro 
canvas.clipRect(50, 50, 150, 150, Region.Op.INTERSECT); //o segundo 
drawScene(canvas);

resultado :

Começando em (10,10) e (50,50) sucessivamente, dois retângulos de 100*100 são cortados e o resultado do corte é:  Interseção de A e B = Parte da interseção de A e B


Op. UNIÃO

canvas.clipRect(10, 10, 110, 110); //o primeiro 
canvas.clipRect(40, 40, 140, 140, Region.Op.UNION); //o segundo 
drawScene(canvas);

resultado :

Começando em (10,10) e (50,50) sucessivamente, dois retângulos 100*100 são cortados, e o resultado do corte é:  união de A e B = área de A + área de B


Op. XOR :

canvas.clipRect(10, 10, 110, 110); //o primeiro 
canvas.clipRect(50, 50, 150, 150, Region.Op.XOR); //o segundo 
drawScene(canvas);

resultado :

Começando em (10,10) e (50,50) sucessivamente, dois retângulos de 100*100 são cortados e o resultado do corte é: Conjunto complementar de A  e B = coleção de A e B - coleção de interseção de A e B


Op.REVERSE_DIFFERENCE

canvas.clipRect(10, 10, 110, 110); //o primeiro 
canvas.clipRect(50, 50, 150, 150, Region.Op.REVERSE_DIFFERENCE); //o segundo 
drawScene(canvas);

resultado :

Começando em (10,10) e (50,50) sucessivamente, dois retângulos 100*100 são cortados, e o resultado do corte é:  diferença de B e A = B - interseção de A e B


Op.SUBSTITUIR

canvas.clipRect(10, 10, 110, 110); //o primeiro 
canvas.clipRect(50, 50, 150, 150, Region.Op.REPLACE); //o segundo 
drawScene(canvas);

resultado :

Iniciado em (10,10) e (50,50) sucessivamente, corte dois retângulos de 100*100, o resultado do corte é: Independentemente do  status da coleção de A e B, o intervalo de B será exibido em sua totalidade, se Se houver uma interseção com A, a faixa de interseção de A será percorrida;


Exemplo de uso de 2.Region.Op:

Os exemplos referem-se a: Android 2D Graphics Learning (2), Canvas Part 2, Canvas Clipping and Region, RegionIterator

Diagrama de efeito de execução :

A parte principal do código MyView.java:

/** 
 * Criado por Jay em 10/11/2015 0010. 
 */ 
public class MyView extends View{ 

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

    private boolean status = HIDE;//Mostra ou esconde o status, o primeiro é HIDE 
    private static final boolean SHOW = true;//Mostra a imagem 
    private static final boolean HIDE = false;//Oculta a imagem 

    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 = largura = mBitmap.getWidth(); 
        altura = 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 <= altura) {//计算clip的区域
            if (i % 2 == 0) { 
                region.union(new Rect(0, i * CLIP_HEIGHT, limitLength, (i + 1) * CLIP_HEIGHT)) ; 
            } outro {
                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) {//Se 
            limitLength estiver oculto neste momento -= 10; 
            if(limitLength <= 0) 
                status=SHOW; 
        } else {//Se 
            limitLength for exibido neste momento += 5; 
            if(limitLength >= largura) 
                status=OCULTAR; 
        } 
        invalidar(); 
    } 
}

Realizar análise :

Obtenha a largura e a altura durante a inicialização e, em seguida, faça um loop. Pode-se entender que a imagem é dividida em linhas. A condição do loop é: i * a altura de cada linha não é maior que a altura e, em seguida, as linhas são divididas em dois casos. A união da região é chamada. Na verdade, é apenas o método de corte do UNINO. Finalmente, ele julga se a imagem é exibida neste momento e lida com as situações ocultas e exibidas de maneira diferente e, finalmente, chama invalidate( ) para redesenhar! É bem simples, entenda você mesmo~

Outra coisa a dizer: a transformação da tela não tem efeito no clipRegion


3. Explicação detalhada do método clipRect:

clipRect fornece sete métodos sobrecarregados:

Os parâmetros são introduzidos da seguinte forma :

rect : objeto Rect, usado para definir o intervalo da área de recorte, Rect e RectF têm funções semelhantes, mas a precisão e os métodos fornecidos são diferentes

esquerda : a posição esquerda da área de recorte retangular

top : a posição superior da área de recorte retangular

direita : a posição certa da área de recorte retangular

inferior : a posição inferior da área de recorte retangular

op : o método de combinação da área de recorte

Os quatro valores acima podem ser ponto flutuante ou inteiro

Exemplo de uso :

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

canvas.translate(300,300); 
canvas.clipRect(100, 100, 300, 300); //Define o intervalo de exibição 
canvas.drawColor(Color.WHITE); //Fundo branco 
canvas.drawText("Double 11, continue a comer minha comida de cachorro...", 150, 300, mPaint); //Desenha uma linha

Resultado da execução :

Do exemplo acima, não sei se você encontrou? clipRect será afetado pela transformação Canvas, e a área branca é a área que não gasta, então o que clipRect clips é a tela, e nosso desenho é executado nessa tela recortada! Exceder esta área não será exibido!


4. Explicação detalhada do método clipPath:

Comparado com clipRect, clipPath tem apenas dois métodos sobrecarregados, e o método de uso é muito simples, basta desenhar um caminho sozinho e passá-lo!

Exemplo de uso :

Aqui está um exemplo de reutilização do ImageView circular que escrevemos no ImageView antes ~

Código de implementação :

ImageView personalizado: RoundImageView.java

/** 
 * Criado por coder-pig em 18/07/2015 0018. 
 */ 
public class RoundImageView extends ImageView { 

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


    //Exibição de 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, nulo, mRect, mPaint);
        canvas.restore(); 
    } 
}

Código do layout: activity_main.xml :

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

MainActivity.java :

public class MainActivity extends AppCompatActivity { 

    private RoundImageView img_round; 

    @Override 
    void protegido onCreate(Pacote salvadoInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.activity_main); 
        img_round = (RoundImageView) findViewById(R.id.img_round); 
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.meinv); 
        img_round.setBitmap(bitmap); 
    } 
}

Além disso, o ImageView arredondado feito por este método terá aliasing óbvio. Mesmo se você definir anti-aliasing para Paint e Canvas, é inútil~ Se você tiver requisitos altos, poderá usar Xfermode-PorterDuff para definir a mistura de imagem para alcançá-lo . Basicamente não há aliasing. Visível: Paint API do Android - Explicação detalhada do Xfermode e PorterDuff (3)

Acho que você gosta

Origin blog.csdn.net/leyang0910/article/details/131828049
Recomendado
Clasificación