Масштабирование макета с неизменным соотношением сторон в Android - PullRequest
3 голосов
/ 23 августа 2011

Я хочу создать графический интерфейс для моего приложения, который по сути является фоновым изображением с некоторыми элементами управления поверх него. Важной (и хитрой) частью является то, что фоновое изображение должно сохранять соотношение сторон и масштаб (с черными границами, если оно не идеально подходит), и что элементы управления выровнены с определенными частями фонового изображения.

Я думал о том, чтобы решить эту проблему, унаследовав AbsoluteLayout (или мою копию, поскольку она устарела), правильно масштабировав / разместив ее и заставив нарисовать мое фоновое изображение. Затем я бы разместил его дочерние элементы в соответствии с «масштабированными абсолютными позициями», используя коэффициент масштабирования [Измеренный размер макета] / [Исходный размер фонового изображения].

Мой вопрос: есть ли лучший способ сделать это? Кажется, это сложный способ сделать что-то, что, как я считаю, встречается относительно часто? (Выравнивание изображения кнопок на пикселе фонового изображения отлично). Я благодарен за все советы и предложения.


В итоге я использовал вышеуказанную стратегию. Для завершения вот что я сделал:

Я создал класс ScalingLayout, расширяющий AbsoluteLayout, и добавил два атрибута xml, которые позволяют мне указывать «виртуальные измерения» для макета. Это те измерения, по которым я размещаю свои виды, и макет обеспечивает правильное масштабирование этих относительных положений при масштабировании всего макета. Так в xml это выглядит так:

<ScalingLayout
    mynamespace:virtualWidth="100"
    mynamespace:virtualHeight="100"
    ...
>

Для получения информации о том, как определить пользовательские атрибуты xml и получить эти значения в конструкторе класса, проверьте этот вопрос: Определение пользовательских атрибутов

Более того, я переопределил «Измерить и выложить» в моем ScalingLayout.

// Overridden to retain aspect of this layout view
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {
    double aspect = getSize(widthMeasureSpec) / (double)getSize(heightMeasureSpec);
    // Those are from XML layout
    double virtualAspect = _virtualWidth / (double)_virtualHeight;
    int width, height;

    measureChildren(widthMeasureSpec, heightMeasureSpec);

    if(aspect > virtualAspect) {
        height = getSize(heightMeasureSpec);
        width = height * virtualAspect;
    } else {
        width = getSize(widthMeasureSpec);
        height = width / virtualAspect;
    }

    setMeasuredDimension(width, height);
}

...

protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
    double factor = (right - left) / (double)_virtualWidth;

    nchildren = getChildCount();

    for(int i = 0; i < nchildren; i++) {
        View child = getChildAt(i);
        LayoutParams lp = child.getLayoutParams();
        // Scale child according to given space
        child.layout(lp.x * factor,
                     lp.y * factor,
                     (lp.x + child.getMeasuredWidth()) * factor,
                     (lp.y + child.getMeasuredHeight()) * factor );
    }
}

Теперь просто добавьте представления в XML и укажите размеры и позиции так же, как для AbsoluteLayout, но подумайте о виртуальных измерениях.

...