LayerDrawable: это можно сделать более эффективно?
У меня есть ImageView
, полная ширина и ширина: высота = 3:1, назовем это 1200 х 400. Я хочу показать два Drawable
в ImageView
Оба из которых известны только во время выполнения. Один из выдвижных ящиков должен быть помещен в ImageView
в соответствии с "разбивкой по центру" (в предположении, что ширина рисования имеет ширину: высота> 3, что означает точную подгонку ширины и обрезку сверху и снизу), другая должна быть отцентрирована и масштабирована в соответствии с пользовательским коэффициентом.
У меня есть некоторый код, который делает это, но он кажется мне излишне сложным; Я только мог заставить его работать как хотел, когда я создаю новый Bitmap
от LayerDrawable
, затем BitmapDrawable
Исходя из этого, и снова установите желаемые границы 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;
}
(Я тестировал с битмапом bm1 2400 x 1200 пикселей и битмапом bm2 800 x 300 пикселей.)
Теперь, если я просто использую это LayerDrawable
, вот так
myImageView.setImageDrawable(layd);
ImageView
не будет иметь желаемого размера (высота меняется.) Если я снова установлю макет с LayoutParameters
Я могу помешать этому, но в этом случае рисунки отображаются неправильно. Если вместо этого я делаю это
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);
оно работает.
Вот полный код на GitHub
1 ответ
Я хотел бы написать свой собственный Drawable
класс, который не так сложно, как кажется. Просто простирайся от Drawable
и переопределить draw()
где вы выполняете почти те же вычисления, что и в коде, который вырезали, просто для рисования в растровые (многоуровневые) с требуемым соотношением сторон. Canvas.drawBitmap (), кажется, работает для вашей проблемы.