2011-03-08 2 views
3

J'essaie de créer une ombre de réflexion et j'ai trouvé un problème.Android: Shader se comporte différemment dans 'onDraw (canvas)' et 'new Canvas (bitmap)'

S'il vous plaît trouver le code ci-dessous à mon avis personnalisé:

@Override 
protected void onDraw(Canvas canvas) { 
    //prepare 
    canvas.drawColor(Color.GRAY); 
    Bitmap source = BitmapFactory.decodeResource(getResources(), R.drawable.icon); 

    //First Column 
    canvas.drawBitmap(source, 0, 0, new Paint()); 

    //2nd Column 
    canvas.drawBitmap(source, source.getWidth(), 0, new Paint()); 

    //Reflection 
    Matrix matrix = new Matrix(); 
    matrix.preScale(1.0f, -1.0f); 
    matrix.postTranslate(source.getWidth(), source.getHeight()*2); 
    canvas.drawBitmap(source, matrix, new Paint()); 

    Paint paint2 = new Paint(); 
    LinearGradient shader = new LinearGradient(
      source.getWidth()*3/2, 
      source.getHeight(), 
      source.getWidth()*3/2, 
      source.getHeight()*2, 
      0x7FFFFFFF, 0x00FFFFFF, TileMode.CLAMP); 
    paint2.setShader(shader); 
    paint2.setXfermode(new PorterDuffXfermode(
      android.graphics.PorterDuff.Mode.DST_IN)); 
    canvas.drawRect(
      source.getWidth(), 
      source.getHeight(), 
      source.getWidth()*2, 
      source.getHeight()*2, 
      paint2); 

    //3rd Column 
    Bitmap bitmap = Bitmap.createBitmap(source.getWidth(), source.getHeight()*2, Config.ARGB_8888); 
    Canvas canvas2 = new Canvas(bitmap); 
    canvas2.drawBitmap(source, 0, 0, new Paint()); 
    matrix = new Matrix(); 
    matrix.preScale(1.0f, -1.0f); 
    matrix.postTranslate(0, source.getHeight()*2); 
    canvas2.drawBitmap(source, matrix, new Paint()); 


    paint2 = new Paint(); 
    shader = new LinearGradient(
      source.getWidth()*1/2, 
      source.getHeight(), 
      source.getWidth()*1/2, 
      source.getHeight()*2, 
      0x7FFFFFFF, 0x00FFFFFF, TileMode.CLAMP); 
    paint2.setShader(shader); 
    paint2.setXfermode(new PorterDuffXfermode(
      android.graphics.PorterDuff.Mode.DST_IN)); 
    canvas2.drawRect(
      0, 
      source.getHeight(), 
      source.getWidth(), 
      source.getHeight()*2, 
      paint2); 

    canvas.drawBitmap(bitmap, source.getWidth()*2,0, new Paint()); 
} 

Je fais même en toile (que je suis arrivé de onDraw(canvas)) et Canvas2 (qui a créé à l'aide new Canvas(bitmap))

Mais, à la fois dessin effet de shader différent comme suit: different shader effect

Pourquoi les effets de shader sont-ils différents?

Répondre

3

Compte tenu du rectangle noir dans la deuxième colonne:

PorterDuff.MODE.DST_IN est défini comme [* Sa Da, Sa * DC]. Puisque les pixels de destination sont un gris opaque constant (Da = 1), le canal alpha du résultat sera défini sur le canal alpha de votre dégradé linéaire, qui est compris entre 0,5 et 1.

Et il y a votre problème ici ... dans la deuxième colonne, vous définissez les pixels de votre fenêtre en partie transparente. Que montre à travers de dessous? L'arrière-plan de la fenêtre, qui est toujours le noir par défaut.

Dans la troisième colonne, vous tracez d'abord vers un bitmap hors écran, puis vous dessinez ensuite le bitmap hors écran partiellement transparent dans le canevas de fenêtre. Cela fonctionne parce que les pixels entrants (à partir du bitmap hors écran) ne remplacent pas complètement les pixels déjà présents mais sont mélangés avec le tampon de destination (en termes de PorterDuff je pense que c'est équivalent à SRC_ATOP).

+0

Merci pour votre explication. –

+0

Merci pour votre explication. Mais encore je ne suis pas clair sur la source et la destination, La destination n'est pas l'état de la toile avant l'appel drawRect() (je veux dire, une toile avec l'image dessinée au-dessus de cela). Plutôt l'état quand il a été créé. J'ai changé le code source de la 3ème colonne en tant que \t \t // 3ème colonne \t \t Bitmap bitmap = Bitmap.createBitmap (source.getWidth(), source.getHeight() * 2, Config.RGB_565); \t \t bitmap.eraseColor (Color.GRAY); alors obtenu la même que la 2ème colonne. Il semble que nous ne pouvions pas changer le canevas d'onDraw (canevas) pour qu'il se comporte comme un canevas bitmap hors écran? –

+0

Si vous utilisez Config.RGB_565, vous supprimez le canal alpha du bitmap hors écran. Il ne peut donc pas être fusionné lorsqu'il est dessiné sur le canevas de la fenêtre. Il va simplement remplacer les pixels de destination. –