Повернуть вид иерархии на 90 градусов - PullRequest
35 голосов
/ 10 августа 2010

Я работаю над подклассом FrameLayout, который должен повернуть все свои дочерние элементы на 90 градусов.Я делаю это для того, чтобы преодолеть ограничение камеры только в альбомной ориентации, присутствующее в Android 2.1 и ниже, благодаря тому, что действие находится в альбомной ориентации, но помещаю наложение моей камеры в это наложение кадра, чтобы оно выглядело, как если бы оно было портретным (вот как Layar делает это ) Для этого я адаптирую код Джеффа Шарки для поворота видов.Моя проблема в том, что я могу вращать Framelayout, но я не могу изменить его размер, чтобы соответствовать новым измерениям.Таким образом, на моем g1 вместо портретного вида с разрешением 320x480 по сравнению с видом на камеру с разрешением 480x320 в центре я получаю прямоугольник 320x320, показывающий мой портретный вид с обрезанными сторонами.

Вот мой код:

public class RotateLayout extends FrameLayout {
    private Matrix mForward = new Matrix();
    private Matrix mReverse = new Matrix();
    private float[] mTemp = new float[2];

    public RotateLayout(Context context) {
        super(context);
    }

    public RotateLayout(Context context, AttributeSet attrs) {
        super(context, attrs);

    }


    /* (non-Javadoc)
     * @see android.widget.FrameLayout#onMeasure(int, int)
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //This didn't work:
        //super.onMeasure(heightMeasureSpec, widthMeasureSpec);
    }

    /* (non-Javadoc)
     * @see android.widget.FrameLayout#onSizeChanged(int, int, int, int)
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        canvas.rotate(270, getWidth()/2, getHeight()/2);
        //This code will stretch the canvas to accommodate the new screen size. This is not what I want.
        //float scaleX=(float)getHeight()/getWidth();
        //float scaleY=(float)getWidth()/getHeight();
        //canvas.scale(scaleX, scaleY,  getWidth()/2, getHeight()/2);
        mForward = canvas.getMatrix();
        mForward.invert(mReverse);
        canvas.save();
        canvas.setMatrix(mForward); //This is the matrix we need to use for proper positioning of touch events
        super.dispatchDraw(canvas);
        canvas.restore();
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        final float[] temp = mTemp;
        temp[0] = event.getX();
        temp[1] = event.getY();

        mReverse.mapPoints(temp);

        event.setLocation(temp[0], temp[1]);
        return super.dispatchTouchEvent(event);
    }
}

Я попытался переопределить OnMeasure, чтобы переключить размеры X и Y в View, но не смог заставить это работать.Будем благодарны за любую помощь, которую вы можете оказать.

Ответы [ 6 ]

39 голосов
/ 07 января 2011

У меня была такая же проблема, и мне удалось ее решить. Вместо того, чтобы вращать каждый вид или макет вручную, я использовал LayoutAnimationController.

Во-первых, поместите файл в / res / anim / с именем revolution.xml

<?xml version="1.0" encoding="utf-8"?>
<rotate
 xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromDegrees="0"
    android:toDegrees="-90"
    android:pivotX="50%"
    android:pivotY="50%"
    android:duration="0" android:fillAfter="true">
</rotate>

Затем в своей деятельности по созданию выполните

.
  @Override
  public void onCreate(Bundle icicle) {
  super.onCreate(icicle);

     setContentView(R.layout.myscreen);

     Animation rotateAnim = AnimationUtils.loadAnimation(this, R.anim.rotation);
     LayoutAnimationController animController = new LayoutAnimationController(rotateAnim, 0);
     FrameLayout layout = (FrameLayout)findViewById(R.id.MyScreen_ContentLayout);
     layout.setLayoutAnimation(animController);
 }

Если вы хотите повернуть элементы, которые находятся над видом предварительного просмотра камеры (SurfaceHolder), просто поместите FrameLayout над SurfaceHolder, поместите все ваши элементы в этот FrameLayout и вызовите Layout «MyScreen_ContentLayout». Готово.

Надеюсь, это помогло кому-то, у меня ушло много времени, чтобы собрать все вместе.

7 голосов
/ 28 января 2013

Используя API уровня 11 и выше, вы можете использовать метод setRotation(degreesFloat);, чтобы программно изменить поворот представления, или вы можете использовать атрибут XML android:rotation="", чтобы изменить его в своем XML. Существуют также методы / атрибуты для изменения только значений X или Y вращения представления: Документы Android - View (setRotation) .

Так что в настоящее время, пока вы используете API уровня 11 или выше, вы должны иметь возможность применить вращение к узлу макета оболочки. Однако вам, вероятно, также придется изменить размеры макета верхнего уровня, чтобы они соответствовали размерам, которые вы хотите после поворота. То есть если у вас есть книжный вид с размерами 800x1280, вам придется изменить его на 1280x800, чтобы он выровнялся после поворота в альбомную ориентацию.

3 голосов
/ 14 апреля 2014

Используя эту библиотеку, вы можете вращать всю иерархию представлений https://github.com/rongi/rotate-layout

Как это

enter image description here

1 голос
/ 04 ноября 2016

Это то, что сработало для меня в целом.

private void init() {
    setRotation(90f);
}

public YourViewOrViewGroup(final Context context) {
    super(context);
    init();
}

... (all the View/ViewGroup constructors) ...

@Override
protected void onLayout(final boolean changed, final int l, final int t, final int r, final int b) {
    super.onLayout(changed, l, t, r, b);

    final int width = getWidth();
    final int height = getHeight();
    final int offset = Math.abs(width - height) / 2;
    setTranslationX(-offset);
    setTranslationY(offset);
}

@Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
    super.onMeasure(heightMeasureSpec, widthMeasureSpec);
}

То, что вы хотите сделать, это поменять местами ширину с высотой, а затем установить смещения X & Y, чтобы после перехода в полноэкранный видвращение.

Выше приведена версия с альбомным поворотом.Для достижения перевернутого ландшафта просто примените вращение на 270 градусов.Вы можете либо изменить код внутри фрагмента, либо применить вращение снаружи более общим способом, т.е.

final YourViewOrViewGroup layout = inflater.inflate(...);
if (currentOrientation.isInverted()) {
    layout.setRotation(layout.getRotation + 180f);
}

, чтобы вы могли встроить повернутый View / ViewGroup в определение xml и раздувать «порт».и «наземные» версии, когда ориентация экрана изменяется, но это, кажется, выходит за рамки этой темы.

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

0 голосов
/ 30 мая 2013

Попробуйте отключить дочернее обрезание корня вашего представления: вызовите setClipChildren(false) для родителя вашего RotateLayout и в методе onMeasure вашего RotateLayout поместите эти строки:

super.onMeasure(heightMeasureSpec, widthMeasureSpec);
setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());

У меня в принципе та же проблемапоскольку вы и я до сих пор не проверили свое решение - я сделаю это завтра и скажу, работает ли оно правильно.

0 голосов
/ 17 сентября 2011

Я думаю, что вы забыли одну строчку в своем onMeasure.

@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
     super.onMeasure(heightMeasureSpec, widthMeasureSpec);
     setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
}

Взято из кода для вертикальной панели поиска здесь: Как мне получить работающий вертикальный SeekBar в Android?

Возможно, вам придется поиграться с getMeasuredHeight (), чтобы сделать правильный размер экрана.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...