LayerDrawable:这可以更有效地完成吗?
Posted
技术标签:
【中文标题】LayerDrawable:这可以更有效地完成吗?【英文标题】:LayerDrawable: can this be done more efficiently? 【发布时间】:2015-03-26 18:51:02 【问题描述】:我有一个ImageView
,全宽,width:height = 3:1,我们称它为 1200 x 400。我想在ImageView
中显示两个Drawable
s,这两个都是只有已知的在运行时。应根据“center-crop”将其中一个可绘制对象放入ImageView
(假设可绘制对象的宽度:高度> 3,这意味着使宽度完全适合并裁剪顶部和底部),另一个应居中并按自定义因子缩放。
我有一些代码可以做到这一点,但对我来说似乎不必要地复杂;当我从LayerDrawable
创建一个新的Bitmap
,然后从该BitmapDrawable
创建一个新的Bitmap
并在BitmapDrawable
上再次设置所需的边界时,我只能让它按需要工作,尽管我已经设置了边界在LayerDrawable
- 但如果我不执行额外的步骤,这些界限就会被忽略。我更喜欢生成LayerDrawable
,以便我可以像在.setImageDrawable()
中一样使用它,但我不知道如何。如果我尝试,android 会做什么对我来说没有任何意义。我做错了什么?
这就是我制作LayerDrawable
的方法
double divide(int k, int n)
return ((double)k)/n;
int verticalPaddingForHorizontalFit(int viewWidth, int viewHeight, int drawableWidth, int drawableHeight)
// you want to draw a drawable into a view, with an exact match in the width. Then either [1] or [2]
// [1] the view is taller than the drawable (i.e., height/width bigger for the view)
// --> method result is positive,
// and gives the amount of padding top and bottom
// [2] the drawable is taller
// --> method result is negative,
// and gives (minus) the amount that needs to be clipped from top and bottom
// such that the drawable is vertically centered
double viewAspect = divide(viewHeight, viewWidth );
double drawableAspect = divide(drawableHeight, drawableWidth);
return (int)Math.round(0.5 * viewWidth * (viewAspect - drawableAspect));
int[] paddingWhenCenteredAt(int viewWidth, int viewHeight, int drawableWidth, int drawableHeight, double drawableScale, int centerX, int centerY)
// scale the drawable with drawableScale, and put it into the view
// such that the center of the drawable has coordinates (centerX, centerY)
// return the padding needed as array of left, top, right, bottom, in that order
// negative values indicating clipping instead of padding
double w = drawableScale * drawableWidth;
double h = drawableScale * drawableHeight;
double left = centerX - 0.5*w;
double right = viewWidth - (centerX + 0.5*w);
double top = centerY - 0.5*h;
double bottom = viewHeight - (centerY + 0.5*h);
return new int[](int)Math.round(left), (int)Math.round(top), (int)Math.round(right), (int)Math.round(bottom);
LayerDrawable makeLayerDrawable(Resources r, int outputWidth, int outputHeight, Bitmap bm1, Bitmap bm2)
Drawable[] layers = new Drawable[2];
BitmapDrawable bmd1 = new BitmapDrawable(r, bm1);
int width1 = bmd1.getIntrinsicWidth();
int height1 = bmd1.getIntrinsicHeight();
layers[0] = bmd1;
BitmapDrawable bmd2 = new BitmapDrawable(r, bm2);
int width2 = bmd2.getIntrinsicWidth();
int height2 = bmd2.getIntrinsicHeight();
layers[1] = bmd2;
LayerDrawable result = new LayerDrawable(layers);
int vPad = verticalPaddingForHorizontalFit(outputWidth, outputHeight, width1, height1);
result.setLayerInset(0, 0, vPad, 0, vPad);
int[] ltrb = paddingWhenCenteredAt(outputWidth, outputHeight, width2, height2, 0.5, outputWidth/2, outputHeight/2);
result.setLayerInset(1, ltrb[0], ltrb[1], ltrb[2], ltrb[3]);
result.setBounds(0, 0, outputWidth, outputHeight);
return result;
(我使用 Bitmap bm1 2400 x 1200 像素和 Bitmap bm2 800 x 300 像素进行了测试。)
现在,如果我只是使用 LayerDrawable
,就像这样
myImageView.setImageDrawable(layd);
ImageView
将没有所需的大小(高度变化。)如果我用LayoutParameters
再次设置布局,我可以防止这种情况发生,但是,drawables 没有正确显示。如果相反,我会这样做
LayerDrawable layd = makeLayerDrawable(r, outputWidth, outputHeight, bm1, bm2);
Bitmap b = Bitmap.createBitmap(outputWidth, outputHeight, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(b);
layd.draw(canvas);
BitmapDrawable result = new BitmapDrawable(getResources(), b);
result.setBounds(0, 0, outputWidth, outputHeight);
myImageView.setImageDrawable(result);
它有效。
Here是github上的完整代码
【问题讨论】:
ImageView 在可绘制图像上调用 setBounds() 作为布局的一部分——手动调用它来尝试设置边界不会有任何效果。您应该考虑在 BitmapDrawable 图层上设置gravity。 @alanv。 1)我认为重力对我的目的不够灵活。其中一个drawable既不在中心也不在任何角落。 2)我知道我想要视图的像素尺寸是什么(screenWidth x screenWidth/3) - 有没有办法告诉 ImageView 剪掉试图比我更聪明,而不是调用 setBounds()?跨度> 您需要覆盖 ImageView 的默认测量和布局。下面的答案建议编写自己的 Drawable 可能是最好的选择,但您最好将 LayerDrawable 子类化并覆盖 onBoundsChange() 方法以在各个图层上执行自己的 setBounds() 调用。 【参考方案1】:我会考虑编写自己的 Drawable
课程,这并不像看起来那么难。只需从Drawable
扩展并覆盖draw()
,您可以在其中执行与您在代码中所做的几乎相同的计算,该代码只是为了绘制到具有所需纵横比的分层(堆叠)位图。 Canvas.drawBitmap() 似乎可以解决您的问题。
【讨论】:
以上是关于LayerDrawable:这可以更有效地完成吗?的主要内容,如果未能解决你的问题,请参考以下文章
由于变量被更频繁地释放,使较小的函数通常在内存方面更有效吗? [关闭]