android - 使 Canvas 透明

标签 android android-canvas surfaceview

在我的应用程序中,我有一个带有粒子爆炸动画的表面 View 。我试图使该表面 View 透明。透明化后,爆炸动画有问题。我附上了原始动画的屏幕截图以及使表面 View 透明后的屏幕截图。当设置背景颜色为黑色时,它工作正常。

Original animation

After making surface view transparent

主 Activity .java

public class MainActivity extends Activity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        LinearLayout surface = (LinearLayout)findViewById(R.id.middleSurface);
        surface.addView(new MainGamePanel(this));

        }
    }

主游戏面板.java

 public class MainGamePanel extends SurfaceView implements
        SurfaceHolder.Callback {

    private static final String TAG = MainGamePanel.class.getSimpleName();

    private static final int EXPLOSION_SIZE = 200;

    private MainThread thread;
    private Explosion explosion;

    // the fps to be displayed
    private String avgFps;
    public void setAvgFps(String avgFps) {
        this.avgFps = avgFps;
    }

    public MainGamePanel(Context context) {
        super(context);
        // adding the callback (this) to the surface holder to intercept events
         this.setBackgroundColor(Color.TRANSPARENT); //To make canvas transparent                
          this.setZOrderOnTop(true); //To make canvas transparent                
          getHolder().setFormat(PixelFormat.TRANSPARENT); //To make canvas transparent!

        getHolder().addCallback(this);

        // make the GamePanel focusable so it can handle events
        setFocusable(true);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // create the game loop thread
        thread = new MainThread(getHolder(), this);

        // at this point the surface is created and
        // we can safely start the game loop
        thread.setRunning(true);
        thread.start();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        Log.d(TAG, "Surface is being destroyed");
        // tell the thread to shut down and wait for it to finish
        // this is a clean shutdown
        boolean retry = true;
        while (retry) {
            try {
                thread.setRunning(false);
                thread.join();
                retry = false;
            } catch (InterruptedException e) {
                // try again shutting down the thread
            }
        }
        Log.d(TAG, "Thread was shut down cleanly");
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            // handle touch
            // check if explosion is null or if it is still active
            if (explosion == null || explosion.getState() == Explosion.STATE_DEAD) {
                explosion = new Explosion(EXPLOSION_SIZE, (int)event.getX(), (int)event.getY());
            }
        }
        return true;
    }
    public void render(Canvas canvas) {

        canvas.drawColor(Color.argb(0, 0, 0, 0)); //To make canvas transparent

        // render explosions
        if (explosion != null) {
            explosion.draw(canvas);
        }

        // display fps
        //displayFps(canvas, avgFps);

        // display border
        /*Paint paint = new Paint();
        paint.setColor(Color.GREEN);
        canvas.drawLines(new float[]{
                0,0, canvas.getWidth()-1,0, 
                canvas.getWidth()-1,0, canvas.getWidth()-1,canvas.getHeight()-1, 
                canvas.getWidth()-1,canvas.getHeight()-1, 0,canvas.getHeight()-1,
                0,canvas.getHeight()-1, 0,0
        }, paint);*/
    }

    /**
     * This is the game update method. It iterates through all the objects
     * and calls their update method if they have one or calls specific
     * engine's update method.
     */
    public void update() {
        // update explosions
        if (explosion != null && explosion.isAlive()) {
            explosion.update(getHolder().getSurfaceFrame());
        }
    }

    private void displayFps(Canvas canvas, String fps) {
        if (canvas != null && fps != null) {
            Paint paint = new Paint();
            paint.setARGB(255, 255, 255, 255);
            canvas.drawText(fps, this.getWidth() - 50, 20, paint);
        }
    }

}

爆炸.java

    public class Explosion {

    private static final String TAG = Explosion.class.getSimpleName();

    public static final int STATE_ALIVE     = 0;    // at least 1 particle is alive
    public static final int STATE_DEAD      = 1;    // all particles are dead

    private Particle[] particles;           // particles in the explosion
    private int x, y;                       // the explosion's origin
    private float gravity;                  // the gravity of the explosion (+ upward, - down)
    private float wind;                     // speed of wind on horizontal
    private int size;                       // number of particles
    private int state;                      // whether it's still active or not

    public Explosion(int particleNr, int x, int y) {
        Log.d(TAG, "Explosion created at " + x + "," + y);
        this.state = STATE_ALIVE;
        this.particles = new Particle[particleNr];
        for (int i = 0; i < this.particles.length; i++) {
            Particle p = new Particle(x, y);
            this.particles[i] = p;
        }
        this.size = particleNr;
    }

    public Particle[] getParticles() {
        return particles;
    }
    public void setParticles(Particle[] particles) {
        this.particles = particles;
    }
    public int getX() {
        return x;
    }
    public void setX(int x) {
        this.x = x;
    }
    public int getY() {
        return y;
    }
    public void setY(int y) {
        this.y = y;
    }
    public float getGravity() {
        return gravity;
    }
    public void setGravity(float gravity) {
        this.gravity = gravity;
    }
    public float getWind() {
        return wind;
    }
    public void setWind(float wind) {
        this.wind = wind;
    }
    public int getSize() {
        return size;
    }
    public void setSize(int size) {
        this.size = size;
    }

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
    }

    // helper methods -------------------------
    public boolean isAlive() {
        return this.state == STATE_ALIVE;
    }
    public boolean isDead() {
        return this.state == STATE_DEAD;
    }

    public void update() {
        if (this.state != STATE_DEAD) {
            boolean isDead = true;
            for (int i = 0; i < this.particles.length; i++) {
                if (this.particles[i].isAlive()) {
                    this.particles[i].update();
                    isDead = false;
                }
            }
            if (isDead)
                this.state = STATE_DEAD; 
        }
    }

    public void update(Rect container) {
        if (this.state != STATE_DEAD) {
            boolean isDead = true;
            for (int i = 0; i < this.particles.length; i++) {
                if (this.particles[i].isAlive()) {
                    this.particles[i].update(container);
//                  this.particles[i].update();
                    isDead = false;
                }
            }
            if (isDead)
                this.state = STATE_DEAD; 
        }
    }

    public void draw(Canvas canvas) {
        for(int i = 0; i < this.particles.length; i++) {
            if (this.particles[i].isAlive()) {
                this.particles[i].draw(canvas);
            }
        }
    }
}

粒子.java

 public class Particle {

    public static final int STATE_ALIVE = 0;    // particle is alive
    public static final int STATE_DEAD = 1;     // particle is dead

    public static final int DEFAULT_LIFETIME    = 200;  // play with this
    public static final int MAX_DIMENSION       = 5;    // the maximum width or height
    public static final int MAX_SPEED           = 10;   // maximum speed (per update)

    private int state;          // particle is alive or dead
    private float widht;        // width of the particle
    private float height;       // height of the particle
    private float x, y;         // horizontal and vertical position
    private double xv, yv;      // vertical and horizontal velocity
    private int age;            // current age of the particle
    private int lifetime;       // particle dies when it reaches this value
    private int color;          // the color of the particle
    private Paint paint;        // internal use to avoid instantiation


    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
    }

    public float getWidht() {
        return widht;
    }

    public void setWidht(float widht) {
        this.widht = widht;
    }

    public float getHeight() {
        return height;
    }

    public void setHeight(float height) {
        this.height = height;
    }

    public float getX() {
        return x;
    }

    public void setX(float x) {
        this.x = x;
    }

    public float getY() {
        return y;
    }

    public void setY(float y) {
        this.y = y;
    }

    public double getXv() {
        return xv;
    }

    public void setXv(double xv) {
        this.xv = xv;
    }

    public double getYv() {
        return yv;
    }

    public void setYv(double yv) {
        this.yv = yv;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getLifetime() {
        return lifetime;
    }

    public void setLifetime(int lifetime) {
        this.lifetime = lifetime;
    }

    public int getColor() {
        return color;
    }

    public void setColor(int color) {
        this.color = color;
    }

    // helper methods -------------------------
    public boolean isAlive() {
        return this.state == STATE_ALIVE;
    }
    public boolean isDead() {
        return this.state == STATE_DEAD;
    }

    public Particle(int x, int y) {
        this.x = x;
        this.y = y;
        this.state = Particle.STATE_ALIVE;
        this.widht = rndInt(1, MAX_DIMENSION);
        this.height = this.widht;
//      this.height = rnd(1, MAX_DIMENSION);
        this.lifetime = DEFAULT_LIFETIME;
        this.age = 0;
        this.xv = (rndDbl(0, MAX_SPEED * 2) - MAX_SPEED);
        this.yv = (rndDbl(0, MAX_SPEED * 2) - MAX_SPEED);
        // smoothing out the diagonal speed
        if (xv * xv + yv * yv > MAX_SPEED * MAX_SPEED) {
            xv *= 0.7;
            yv *= 0.7;
        }
        this.color = Color.argb(255, rndInt(0, 255), rndInt(0, 255), rndInt(0, 255));
        this.paint = new Paint(this.color);
    }

    /**
     * Resets the particle
     * @param x
     * @param y
     */
    public void reset(float x, float y) {
        this.state = Particle.STATE_ALIVE;
        this.x = x;
        this.y = y;
        this.age = 0;
    }

    // Return an integer that ranges from min inclusive to max inclusive.
    static int rndInt(int min, int max) {
        return (int) (min + Math.random() * (max - min + 1));
    }

    static double rndDbl(double min, double max) {
        return min + (max - min) * Math.random();
    }

    public void update() {
        if (this.state != STATE_DEAD) {
            this.x += this.xv;
            this.y += this.yv;

            // extract alpha
            int a = this.color >>> 24;
            a -= 2;                             // fade by 5
            if (a <= 0) {                       // if reached transparency kill the particle
                this.state = STATE_DEAD;
            } else {
                this.color = (this.color & 0x00ffffff) + (a << 24);     // set the new alpha
                this.paint.setAlpha(a);
                this.age++;                     // increase the age of the particle
//              this.widht *= 1.05;
//              this.height *= 1.05;
            }
            if (this.age >= this.lifetime) {    // reached the end if its life
                this.state = STATE_DEAD;
            }

            // http://lab.polygonal.de/2007/05/10/bitwise-gems-fast-integer-math/
            //32bit
//          var color:uint = 0xff336699;
//          var a:uint = color >>> 24;
//          var r:uint = color >>> 16 & 0xFF;
//          var g:uint = color >>>  8 & 0xFF;
//          var b:uint = color & 0xFF;

        }
    }

    public void update(Rect container) {
        // update with collision
        if (this.isAlive()) {
            if (this.x <= container.left || this.x >= container.right - this.widht) {
                this.xv *= -1;
            }
            // Bottom is 480 and top is 0 !!!
            if (this.y <= container.top || this.y >= container.bottom - this.height) {
                this.yv *= -1;
            }
        }
        update();
    }

    public void draw(Canvas canvas) {
//      paint.setARGB(255, 128, 255, 50);
        paint.setColor(this.color);
        canvas.drawRect(this.x, this.y, this.x + this.widht, this.y + this.height, paint);
//      canvas.drawCircle(x, y, widht, paint);
    }

}

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"

android:background="#556168"
tools:context="com.offero.MainActivity$PlaceholderFragment" >



<ImageView
    android:id="@+id/imageView4"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scaleType="centerCrop"
    android:src="@drawable/bg" />

<ImageView
    android:id="@+id/imageView2"
    android:layout_width="70dp"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_alignParentRight="true"
    android:layout_marginRight="5dp"
    android:src="@drawable/cloud2" />

<ImageView
    android:id="@+id/imageView1"
    android:layout_width="70dp"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_alignParentLeft="true"
    android:layout_marginLeft="5dp"
    android:src="@drawable/cloud1" />

<ImageView
    android:id="@+id/ImageView02"
    android:layout_width="70dp"
    android:layout_height="wrap_content"
    android:layout_alignLeft="@+id/imageView2"
    android:layout_alignParentBottom="true"
    android:layout_marginRight="5dp"
    android:src="@drawable/cloud2" />

<ImageView
    android:id="@+id/ImageView01"
    android:layout_width="70dp"
    android:layout_height="wrap_content"
    android:layout_alignLeft="@+id/imageView1"
    android:layout_alignParentBottom="true"
    android:layout_marginLeft="5dp"
    android:src="@drawable/cloud1" />

<ImageView
    android:id="@+id/ImageView03"
    android:layout_width="70dp"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_centerHorizontal="true"
    android:src="@drawable/cloud1" />

<ImageView
    android:id="@+id/imageView3"
    android:layout_width="wrap_content"
    android:layout_height="150dp"
    android:layout_centerInParent="true"
    android:src="@drawable/rocket" />

<ImageView
    android:id="@+id/imageView5"
    android:layout_width="wrap_content"
    android:layout_height="58dp"
    android:layout_alignTop="@+id/imageView3"
    android:layout_centerHorizontal="true"
    android:src="@drawable/rocketpeice2" />

<ImageView
    android:id="@+id/imageView6"
    android:layout_width="wrap_content"
    android:layout_height="60dp"
    android:layout_below="@+id/imageView5"
    android:layout_centerHorizontal="true"
    android:src="@drawable/rocketpeice1" />

<ImageView
    android:id="@+id/imageView_star1"
    android:layout_width="wrap_content"
    android:layout_height="10dp"
    android:layout_alignTop="@+id/imageView6"
    android:layout_centerHorizontal="true"
    android:src="@drawable/star" />

<ImageView
    android:id="@+id/imageView_star2"
    android:layout_width="wrap_content"
    android:layout_height="15dp"
    android:layout_alignTop="@+id/imageView6"
    android:layout_centerHorizontal="true"
    android:src="@drawable/star" />

<ImageView
    android:id="@+id/ImageView_star3"
    android:layout_width="wrap_content"
    android:layout_height="7dp"
    android:layout_alignTop="@+id/imageView6"
    android:layout_centerHorizontal="true"
    android:src="@drawable/star" />

<ImageView
    android:id="@+id/ImageView_star4"
    android:layout_width="wrap_content"
    android:layout_height="12dp"
    android:layout_alignBottom="@+id/ImageView_star3"
    android:layout_centerHorizontal="true"
    android:src="@drawable/star" />

<ImageView
    android:id="@+id/ImageView_star5"
    android:layout_width="wrap_content"
    android:layout_height="10dp"
    android:layout_alignLeft="@+id/imageView_star1"
    android:layout_below="@+id/imageView5"
    android:src="@drawable/star" />

<ImageView
    android:id="@+id/ImageView_star6"
    android:layout_width="wrap_content"
    android:layout_height="15dp"
    android:layout_alignLeft="@+id/imageView_star1"
    android:layout_alignTop="@+id/imageView6"
    android:src="@drawable/star" />

<ImageView
    android:id="@+id/ImageView_star7"
    android:layout_width="wrap_content"
    android:layout_height="7dp"
    android:layout_alignLeft="@+id/imageView_star1"
    android:layout_below="@+id/ImageView_star3"
    android:src="@drawable/star" />

<ImageView
    android:id="@+id/ImageView_star8"
    android:layout_width="wrap_content"
    android:layout_height="12dp"
    android:layout_alignLeft="@+id/imageView_star1"
    android:layout_alignTop="@+id/imageView6"
    android:src="@drawable/star" />

<LinearLayout
    android:id="@+id/middleSurface"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
</LinearLayout>

最佳答案

下面的代码在 Canvas 上绘制了一种颜色。

canvas.drawColor(Color.argb(0, 0, 0, 0)); //To make canvas transparent

我假设你之前画过黑色。这将绘制黑色,然后是新的粒子位置。也就是在绘制之间清除 Canvas 。

现在您在两次绘制之间在 Canvas 上进行了清晰的绘制,实际上您什么也没做。因为什么都不画没有效果。

您实际需要做的是清除 Canvas 。

你需要使用代码:

  canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);

这绘制透明,但也告诉它不要与现有粒子合并,而是实际清除它们:) 引用:https://stackoverflow.com/a/10882301/940834

关于android - 使 Canvas 透明,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25075712/

相关文章:

android - ImageView 与 Canvas

android - SurfaceView 的替代品?

android - 将 SQLite 数据库导出到 android 中的 csv 文件

android - 如何部分更新surfaceview?

Android:无法将 VideoView 背景设置为透明

android - 在 Android 中使用 arcTo 创建凹路径

Android SurfaceView 预览太暗

Android SurfaceView Canvas 层

java - 由于字符串太大而无法获取有效负载(base64 图像)

android - onActivityCreated 弃用 : how to add fragments as observers of MainActivity using NavigationComponent