安卓:SurfaceView闪烁 [英] Android: SurfaceView Flickering

查看:422
本文介绍了安卓:SurfaceView闪烁的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有画上一个问题,一个 SurfaceView ,当上了 SurfaceView 移动的位图图像,他们忽悠(或撕裂)。我没有在我的$ C $的C previous迭代这个问题。但现在,我终于得到了位图的比例适当,通过使用一个单独的画布每个位图,这个问题开始出现。这是我的自定义的重要组成部分 SurfaceView 类:

I am having an issue with drawing to a SurfaceView, when the bitmap images on the SurfaceView are moved, they flicker (or tear). I did not have this problem in previous iterations of my code. But now that I finally got the bitmaps to scale properly by using a separate Canvas for each bitmap, this problem started occurring. These are the important parts of my custom SurfaceView class:

public class DrawingSurface extends SurfaceView implements SurfaceHolder.Callback {

    public DrawingSurface(Context context, AttributeSet attributeSet, int defStyle) {
        super(context, attributeSet, defStyle);
        initialize(context);
    }

    private void initialize(Context context) {
        mContext = context;
        getHolder().addCallback(this);
        setFocusable(true);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        mHost = (EditorActivity) mContext;
        Log.d("DrawingSurface", "SURFACE CREATED");
        mDrawingThread = new DrawingThread(this, REFRESH_RATE);
        mDrawingThread.setRunning(true);
        mDrawingThread.start();
        onConfigurationChanged(getResources().getConfiguration());
    }

    public Bitmap createBitmap() {
        Bitmap bitmap = Bitmap.createBitmap(mBitmap);
        Canvas canvas = new Canvas(bitmap);
        Sticker[] stickers = mStickers.toArray(new Sticker[mStickers.size()]);
        for (Sticker sticker : stickers) {
            canvas.drawBitmap(sticker.getBitmap(), new Matrix(), mPaint);
        } return bitmap;
    }

    public void drawSurface(Canvas canvas) {
        Bitmap bitmap = createBitmap();
        mMatrix.setScale(1.0f / mScaleFactor, 1.0f / mScaleFactor);
        canvas.drawBitmap(bitmap, mMatrix, mPaint);
    }

    private void setScaleFactor() {
         mScaleFactor = ((float) mBitmap.getWidth()) / getWidth();
    }

    public void addSticker(int drawableId) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inScaled = false;
        Sticker sticker = new Sticker(
                BitmapFactory.decodeResource(getResources(), drawableId, options),
                new PointF(mBitmap.getWidth(), mBitmap.getHeight()),
                mScaleFactor);
        mActiveSticker = sticker;
        mStickers.add(sticker);
    }
}

这是我的自定义

public class DrawingThread extends Thread {

    private volatile boolean mRunning = false;

    private long mRefreshRate;
    private DrawingSurface mSurface;

    public DrawingThread (DrawingSurface surface, long time) {
        super();
        mSurface = surface;
        mRefreshRate = time;
    }

    public void setRunning (boolean run) {
        mRunning = run;
        Log.d("DrawingThread", "Running: " + mRunning);
    }

    @Override
    public void run() {
        while (mRunning) {
            try {
                sleep(mRefreshRate);
                onSurfaceUpdate();
            } catch (InterruptedException exception) {
                exception.printStackTrace();
            }
        }
    }

    public void onSurfaceChanged(Configuration config, Point fit, float ratio) {
        float width, height;
        if (config.orientation == Configuration.ORIENTATION_LANDSCAPE) {
            width = fit.y * ratio;
            height = fit.y;
        } else if (config.orientation == Configuration.ORIENTATION_PORTRAIT) {
            width = fit.x;
            height = fit.x / ratio;
        } else {
            width = fit.x;
            height = fit.x / ratio;
        } mSurface.getHolder().setFixedSize((int) width, (int) height);
    }

    private void onSurfaceUpdate() {
        Canvas canvas = null;
        try {
            canvas = mSurface.getHolder().lockCanvas();
            synchronized (mSurface.getHolder()) {
                if (canvas != null) {
                    mSurface.drawSurface(canvas);
                }
            }
        } finally {
            if (canvas != null) {
                mSurface.getHolder().unlockCanvasAndPost(canvas);
            }
        }
    }
}

和用于保存每个单独的贴纸类画布位图

And the sticker class used to hold each separate Canvas and Bitmap:

public class Sticker {
    private static final float START_SCALE = 0.5f;
    private static final float MIN_SCALE = 0.3f;
    private static final float MAX_SCALE = 7f;

    private float mScale = 1f;
    private float mScaleFactor;

    private Canvas mCanvas = new Canvas();
    private Bitmap mSticker;
    private Bitmap mSurface;

    private PointF mCenter = new PointF();

    private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    private Matrix mMatrix = new Matrix();

    public Sticker(Bitmap sticker, PointF size, float scaleFactor) {
        mSticker = sticker;

        mSurface = Bitmap.createBitmap((int) size.x, (int) size.y, Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mSurface);
        mCanvas.drawColor(0, PorterDuff.Mode.CLEAR);

        setScaleFactor(scaleFactor);
        postSticker();
    }

    private void postSticker() {
        mMatrix.postScale(START_SCALE, START_SCALE);
        setCenter();
        setTranslate(mCenter.x, mCenter.y);
    }

    public boolean collider(PointF point) {
        int x = (int) (point.x * mScaleFactor);
        int y = (int) (point.y * mScaleFactor);
        int color = mSurface.getPixel(x, y);

        if(color != Color.TRANSPARENT) {
            return true;
        } else {
            return false;
        }
    }

    public Bitmap getBitmap() {
        return mSurface;
    }

    public void flipSticker() {
        Matrix matrix = new Matrix();
        matrix.preScale(-1, 1);
        mSticker = Bitmap.createBitmap(mSticker, 0, 0,
                mSticker.getWidth(), mSticker.getHeight(), matrix, false);
    }

    public void setScaleFactor(float scaleFactor) {
        mScaleFactor = scaleFactor;
    }

    public void setTranslate(float deltaX, float deltaY) {
        mMatrix.postTranslate(deltaX * mScaleFactor, deltaY * mScaleFactor);
        draw();
    }

    public void setScale(float deltaScale, PointF midpoint) {
        mScale *= deltaScale;
        if(MIN_SCALE < mScale && mScale < MAX_SCALE) {
            mMatrix.postScale(deltaScale, deltaScale,
                    midpoint.x * mScaleFactor, midpoint.y * mScaleFactor);
        } draw();
    }

    public void setRotate(float deltaRotate, PointF midpoint) {
        mMatrix.postRotate(deltaRotate, midpoint.x * mScaleFactor, midpoint.y * mScaleFactor);
        draw();
    }

    private void setCenter() {
        float width = (mSurface.getWidth() / 2) - ((mSticker.getWidth() / 2) * START_SCALE);
        float height = (mSurface.getHeight() / 2) - ((mSticker.getHeight() / 2) * START_SCALE);
         mCenter.set(width, height);
    }

    private void draw() {
        mCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
        mCanvas.drawBitmap(mSticker, mMatrix, mPaint);
    }
}

我已发现对计算器同一主题的各种讨论,以及其他网站。他们都得出这样的结论闪烁是由于如何使用 SurfaceView 处理缓冲,用两个表面之间进行切换。该解决方案包括使用一个单独的位图来绘制所有图像先,然后绘制位图到 SurfaceView 的。正如你所看到的,我已经在这样做了我的 createBitmap 方法,但闪烁的存在。

I have found various discussions on the same topic on StackOverflow, as well as other sites. All of them conclude that the flickering is due to how the SurfaceView handles buffering, using two surfaces to swap between. The solution consists of using a separate bitmap to draw all of the images to first, then drawing that bitmap to the SurfaceView. As you can see, I have done this in my createBitmap method, yet the flickering persists.

推荐答案

我觉得闪烁是由于画布绘制位图它被使用之前没有完成在 createBitmap()。我改变了方法 getBitmap()返回的 mSticker 而不是更大的 mSurface (其用于检测其中用户正在触摸),使得被吸入的位图不那么大。我添加的方法 getMatrix()返回 mMatrix 每个贴纸,并使用了在 createBitmap的 canvas.drawBitmap()()方法。这个停止闪烁,即使我用我的贴纸PNG文件都相当大(大部分是1024×1024)。

I think the flickering was due to the Canvas drawing to the bitmap not being finished before it gets used in createBitmap(). I altered the method getBitmap() to return mSticker instead of the much larger mSurface (which is used to detect where the user is touching), so that the bitmap being drawn was not so large. And I added the method getMatrix() to return the mMatrix from each Sticker, and used that for the canvas.drawBitmap() method in createBitmap(). This stopped the flickering, even though the png files I use for my stickers are fairly large (most are 1024 x 1024).

这篇关于安卓:SurfaceView闪烁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆