在屏幕API上重新出现后,ImageView不显示位图< 23

时间:2015-11-26 22:34:07

标签: android android-intent android-activity bitmap imageview

我再次遇到了一个奇怪的android框架问题:
我有一个活动,显示有关对象的详细信息。它被设计成看起来像一个漂浮的"活动,意味着它覆盖了MainActivity,可以通过向用户轻轻滑动来解除。

截图

As you can see, the activity overlays its parent.

它是如何完成的(错误?)

由于将窗口背景设置为@android:color/transparent会导致难看的副作用,因此我使用自定义ImageView作为背景(我使用Chris Banes https://github.com/chrisbanes/philm/blob/master/app/src/main/java/app/philm/in/view/BackdropImageView.java对此进行了修改) :

public class BackdropImageView extends ImageView {
    private static final int MIN_SCRIM_ALPHA = 0x00;
    private static final int MAX_SCRIM_ALPHA = 0xFF;
    private static final int SCRIM_ALPHA_DIFF = MAX_SCRIM_ALPHA - MIN_SCRIM_ALPHA;

    private float mScrimDarkness;
    private float factor;
    private int mScrimColor = Color.BLACK;
    private int mScrollOffset;
    private int mImageOffset;

    private final Paint mScrimPaint;

    public BackdropImageView(Context context) {
        super(context);
        mScrimPaint = new Paint();
        factor = 2;
    }

    public BackdropImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mScrimPaint = new Paint();
        factor = 2;
    }

    private void setScrollOffset(int offset) {
        if (offset != mScrollOffset) {
            mScrollOffset = offset;
            mImageOffset = (int) (-offset / factor);
            offsetTopAndBottom(offset - getTop());

            ViewCompat.postInvalidateOnAnimation(this);
        }
    }

    public void setFactor(float factor) {
        this.factor = factor;
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);

        if (mScrollOffset != 0) {
            offsetTopAndBottom(mScrollOffset - getTop());
        }
    }

    public void setScrimColor(int scrimColor) {
        if (mScrimColor != scrimColor) {
            mScrimColor = scrimColor;

            ViewCompat.postInvalidateOnAnimation(this);
        }
    }

    public void setProgress(int offset, float scrim) {
        mScrimDarkness = ScrollUtils.getFloat(scrim, 0, 1);
        setScrollOffset(offset);
    }

    @Override
    protected void onDraw(@NonNull Canvas canvas) {
        // Update the scrim paint
        mScrimPaint.setColor(ColorUtils.setAlphaComponent(mScrimColor,
                MIN_SCRIM_ALPHA + (int) (SCRIM_ALPHA_DIFF * mScrimDarkness)));

        if (mImageOffset != 0) {
            canvas.save();
            canvas.translate(0f, mImageOffset);
            canvas.clipRect(0f, 0f, canvas.getWidth(), canvas.getHeight() + mImageOffset + 1);
            super.onDraw(canvas);
            canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), mScrimPaint);
            canvas.restore();
        } else {
            super.onDraw(canvas);
            canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), mScrimPaint);
        }
    }
}

当我开始活动时,我会创建当前活动的快照,然后将其保存到缓存中,并通过Intent.putExtra(String key, String value);传递它的路径:

public static Intent createOverlayActivity(Activity activity) {
    Intent startIntent = new Intent(activity, OverlayActivity.class);
    View root = activity.findViewById(android.R.id.content);

    Rect clipRect = new Rect();
    activity.getWindow().getDecorView()
            .getWindowVisibleDisplayFrame(clipRect);

    Bitmap bitmap = Bitmap.createBitmap(
            root.getWidth(),
            root.getHeight(),
            Bitmap.Config.ARGB_8888
    );

    Canvas canvas = new Canvas(bitmap);
    canvas.drawRGB(0xEE, 0xEE, 0xEE);

    // Quick fix for status bar appearing in Lollipop and above
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        canvas.translate(0, -clipRect.top / 2);
        canvas.clipRect(clipRect);
    }
    root.draw(canvas);

    try {
         File file = new File(activity.getCacheDir(), "background.jpg");
         FileOutputStream stream = new FileOutputStream(file);

         bitmap.compress(Bitmap.CompressFormat.JPEG, 50, stream);
         stream.flush();
         stream.close();

         bitmap.recycle();
         startIntent.putExtra("bgBitmap", file.getPath());

         Log.d(TAG, "Rendered background image.");
    } catch (IOException e) {               
        e.printStackTrace();
    }

    return startIntent;
}

OverlayActivity' onCreate()中,我收到了缓存文件的路径,并将位图加载到ImageView

Bitmap screenshot = BitmapFactory.decodeFile(getIntent().getStringExtra("bgBitmap"));
if (screenshot == null) {
    throw new IllegalArgumentException("You have to provide a valid bitmap!");
}

/* BackdropImageView is an ImageView subclass allowing
 *  me to darken the image with a scrim using the slide offset value */
backdropImageView = new BackdropImageView(this);
backdropImageView.setId(android.R.id.background);

backdropImageView.setFactor(1.125f);
backdropImageView.setScrimColor(Color.BLACK);
backdropImageView.setImageBitmap(screenshot);
backdropImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);

问题

正如您在上面的屏幕截图中看到的,它在运行API 23的设备上运行得相当不错,但在下面的设备上。 这里的图像会在活动滑入时显示,直到完全覆盖,但当我再次向下滑动时,图像消失,ImageView只显示一个灰色的实体:

enter image description here

更新

我已经发现问题必须隐藏在BackdropImageView课程的某个地方,因为简单的ImageView有效。

关于什么可能导致这个奇怪的问题的任何想法?

提前致谢!

1 个答案:

答案 0 :(得分:0)

好吧,好像我过分关注实际的图像加载而不是视图本身。

我发现问题与子类中offsetTopAndBottom(offset - getTop());的使用有关。不知怎的,这使得ImageView有时会在Marshmallow之前的Android版本上消失(仍然不确定),尽管它仍然在视图层次结构中的正确位置。

所以这是我的解决方法:
当我删除这些代码行时,它工作正常。因为我需要偏移视图以创建视差滚动效果,所以我将此功能移出视图子类。我现在正在做的只是在View.setTranslationY(float)之前每次在我使用的任何滚动相关回调中调用BackdropImageView.setProgress(int, float)

不知怎的,这完全正常。