我再次遇到了一个奇怪的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);
}
}
}
当我开始活动时,我会创建当前活动的快照,然后将其保存到缓存中,并通过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
只显示一个灰色的实体:
我已经发现问题必须隐藏在BackdropImageView
课程的某个地方,因为简单的ImageView
有效。
关于什么可能导致这个奇怪的问题的任何想法?
提前致谢!
答案 0 :(得分:0)
好吧,好像我过分关注实际的图像加载而不是视图本身。
我发现问题与子类中offsetTopAndBottom(offset - getTop());
的使用有关。不知怎的,这使得ImageView
有时会在Marshmallow之前的Android版本上消失(仍然不确定),尽管它仍然在视图层次结构中的正确位置。
所以这是我的解决方法:
当我删除这些代码行时,它工作正常。因为我需要偏移视图以创建视差滚动效果,所以我将此功能移出视图子类。我现在正在做的只是在View.setTranslationY(float)
之前每次在我使用的任何滚动相关回调中调用BackdropImageView.setProgress(int, float)
。
不知怎的,这完全正常。