【问题标题】:ImageView not showing bitmap after reappearing on screen API < 23ImageView 重新出现在屏幕 API < 23 后不显示位图
【发布时间】:2015-11-26 22:34:06
【问题描述】:

我又遇到了一个奇怪的android框架问题:
我有一个显示对象详细信息的活动。它被设计成看起来像一个“浮动”活动,这意味着它覆盖了MainActivity,并且可以通过从用户那里简单地向下滑动来消除。


截图


它是怎么做的(错了?)

因为将窗口背景设置为@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);
        }
    }
}

当我启动 Activity 时,我会创建当前 Activity 的快照,然后将其保存到缓存中,并通过 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;
}

OverlayActivityonCreate() 中,我收到缓存文件的路径并将位图加载到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 仅显示为纯灰色:


更新

我发现问题必须隐藏在 BackdropImageView 类中的某个地方,因为简单的 ImageView 可以工作。

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

提前致谢!

【问题讨论】:

  • 您是否尝试在 Activity 的 onStart() 事件中添加以下行:backdropImageView.setFactor(1.125f); backdropImageView.setScrimColor(Color.BLACK); backdropImageView.setImageBitmap(screenshot); backdropImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
  • 是的,我试过了。还是不行:(

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


【解决方案1】:

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

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

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

不知何故,这工作得很好。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多