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 (), кажется, работает для вашей проблемы.

Другие вопросы по тегам