Android-在更深层的现有视图上精确绘制ImageView
这是一个很难描述的情况,所以请容忍我。我被要求制作一个有点像这样的“coach marks”屏幕: 然而,在我的例子中,我需要将一些底层图像“拉”到前面,并以不同的颜色显示它们,使它们脱颖而出。在运行时之前,我无法确定这些图像的“帧”是什么。我的方法是添加一个覆盖整个屏幕的黑色半透明视图(我称之为“窗帘”),然后添加我需要的图像,作为窗帘的子视图,并使用不同的颜色。编辑这一部分很容易,我不是在寻求帮助(这就是为什么认为这是建议问题的重复是不正确的) 我不相信我可以使用Android-在更深层的现有视图上精确绘制ImageView,android,view,Android,View,这是一个很难描述的情况,所以请容忍我。我被要求制作一个有点像这样的“coach marks”屏幕: 然而,在我的例子中,我需要将一些底层图像“拉”到前面,并以不同的颜色显示它们,使它们脱颖而出。在运行时之前,我无法确定这些图像的“帧”是什么。我的方法是添加一个覆盖整个屏幕的黑色半透明视图(我称之为“窗帘”),然后添加我需要的图像,作为窗帘的子视图,并使用不同的颜色。编辑这一部分很容易,我不是在寻求帮助(这就是为什么认为这是建议问题的重复是不正确的) 我不相信我可以使用bringToFront(
bringToFront()
或setTranslationZ()
,因为这些方法不会将ImageView
一直带到我的窗帘前面。因此,我想做的是获得图像视图相对于整个屏幕的精确“帧”(其x、y、宽度和高度),然后尝试使用相同的画框添加新的图像视图
了解底层“视图”实际上由多个视图(包括滑动抽屉)组成也很重要,这就是为什么我需要获得相对于屏幕的坐标。我希望这是有道理的
我可以用正确的颜色将新的图像视图
绘制为窗帘的子视图,但图像的位置和大小相差很远。如何在上一个视图的基础上绘制新的ImageView
我也对其他策略持开放态度(因为这个策略似乎不起作用)。谢谢你的帮助
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
ViewTreeObserver vto = mRootview.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
mRootview.getViewTreeObserver().removeOnGlobalLayoutListener(this);
mDrawerLayout.openDrawer(Gravity.LEFT);
RelativeLayout curtain = addOpaqueCurtainToRootView();
int frame[] = getFrameOfExistingImageView();
addNewImageViewOnTopOfEverything(curtain, frame);
}
});
}
private RelativeLayout addOpaqueCurtainToRootView() {
RelativeLayout curtain = new RelativeLayout(context);
RelativeLayout.LayoutParams curtainParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
curtain.setLayoutParams(curtainParams);
curtain.setBackgroundColor(Color.argb(179, 0, 0, 0)); //70% opaque
mRootview.addView(curtain);
return curtain;
}
private int[] getFrameOfExistingImageView() {
// proving that I have a reference to the original image
mCurrentImage.setColorFilter(Color.rgb(255, 0, 0));
int array[] = new int[2];
mCurrentImage.getLocationOnScreen(array);
Log.d(TAG, "width: " + Integer.toString(array[0]));
Log.d(TAG, "height: " + Integer.toString(array[1]));
Log.d(TAG, "x: " + Float.toString(mCurrentImage.getX()));
Log.d(TAG, "y: " + Float.toString(mCurrentImage.getY()));
int frame[] = new int[4]; // x,y,width,height
frame[0] = (int)mCurrentImage.getX();
frame[1] = (int)mCurrentImage.getY();
frame[2] = array[0];
frame[3] = array[1];
return frame;
}
private void addNewImageViewOnTopOfEverything(RelativeLayout curtain, int[] frame) {
ImageView iv = new ImageView(context);
iv.setImageResource(R.drawable.imgView);
iv.setColorFilter(Color.rgb(255, 255, 255));
iv.setX(frame[0]);
iv.setY(frame[1]);
iv.setLayoutParams(new RelativeLayout.LayoutParams(frame[2], frame[3]));
curtain.addView(iv);
}
我明白了。我有两个基本问题 首先,我把
ImageView
的框架搞错了。我需要得到左边和上面的坐标,以及画完后图像的高度和宽度。我就是这样做的(实际上我正在转换为左、上、右、下,但其余的都很简单):
然后,我创建了一个新类来绘制。这是与我的OP最大的不同。最初,我想我可以将其添加为一个新的ImageView
,并将其LayoutParams
设置为我想要的位置。相反,我使用绘制
和画布
来绘制、调整大小和放置:
public class CanvasPainter extends View {
Context mContext;
Drawable mDrawable;
int mFrame[];
int left;
int top;
int right;
int bottom;
int width;
int height;
private final int LEFT = 0;
private final int TOP = 1;
private final int RIGHT = 2;
private final int BOTTOM = 3;
public CanvasPainter(Context context, int frame[], Drawable drawable) {
super(context);
mContext = context;
mFrame = frame;
mDrawable = drawable;
left = frame[LEFT];
top = frame[TOP];
right = frame[RIGHT];
bottom = frame[BOTTOM];
width = right - left;
height = bottom - top;
}
public void onDraw(Canvas canvas) {
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
Bitmap b = ((BitmapDrawable) mDrawable).getBitmap();
Bitmap bitmapResized = Bitmap.createScaledBitmap(b, width, height, false);
canvas.drawBitmap(bitmapResized, left, top, paint);
}
}
所以,把这些放在一起,所有这些都是从onCreate()
这样组织起来的
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
mDrawerLayout.openDrawer(Gravity.LEFT);
ViewTreeObserver vto = mRootview.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
mRootview.getViewTreeObserver().removeOnGlobalLayoutListener(this);
RelativeLayout curtain = addOpaqueCurtainToRootView();
int frame[] = getFrameOfExistingImageView();
Drawable d = ContextCompat.getDrawable(context, R.drawable.imgView);
CanvasPainter canvasPainter = new CanvasPainter(context, mCurrentImg, frame, d);
curtain.addView(canvasPainter);
}
});
}
这可能是一个有点模糊的问题,但我希望这能帮助别人。try@user5599807的可能重复-不是重复。那篇文章只是问了一个非常简单的问题,那就是如何在半透明的背景下绘制视图。我已经(很容易)做到了。我的问题是如何在新视图上以精确的位置和大小放置子视图。@pskink-谢谢。当我阅读这段代码时,它似乎建议解决方案是a)获取对图像视图的引用,b)将其从初始父视图中删除,然后c)将其添加到新的半透明视图中。但这并不能解决如何在新父视图中定位和调整图像视图大小的问题,对吗?我可能不明白如何正确地实施这个建议。还有比我看到的更多的吗?非常感谢您提出的进一步建议。我很感激!无需
ImageView
所需:在dispatchDraw
方法中绘制您想要的任何东西,您可以调用例如canvas.drawBitmap
,MyDecorView
占据包括操作栏在内的所有屏幕,因此您不需要以任何方式定位它,只需在调用setContentView
后调用addmetheviewtree
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
mDrawerLayout.openDrawer(Gravity.LEFT);
ViewTreeObserver vto = mRootview.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
mRootview.getViewTreeObserver().removeOnGlobalLayoutListener(this);
RelativeLayout curtain = addOpaqueCurtainToRootView();
int frame[] = getFrameOfExistingImageView();
Drawable d = ContextCompat.getDrawable(context, R.drawable.imgView);
CanvasPainter canvasPainter = new CanvasPainter(context, mCurrentImg, frame, d);
curtain.addView(canvasPainter);
}
});
}