Почему представление перетаскивается с возвратом ViewDragHelper в исходное положение на макете ()?

Я использую пользовательскую расширяемую панель действий в своей игре. Я использую ViewDragHelper для обработки перетаскивания и отображения в виде бара, который содержится в подклассе LinearLayout I для присоединения ViewDragHelper.

Следующие ссылки оказали большую помощь для достижения этой цели:

  • Учебное пособие по ViewDragHelper: http://flavienlaurent.com/blog/2013/08/28/each-navigation-drawer-hides-a-viewdraghelper/
  • Освоение сенсорной системы Android: https://www.youtube.com/watch?v=EZAoJU-nUyI (который дал мне ключи, чтобы сделать просмотр доступным и перетаскиваемым)

Единственная проблема, с которой я сталкиваюсь, – это поведение макета () моего родительского LinearLayout: при каждом вызове layout() / onLayout() перетаскиваемая / расширяемая панель действий сбрасывается в исходное положение (значение, установленное в XML-макет).

Почему это ?

(В моем layout() опыта layout() никогда не смешивается с позициями просмотров, которые уже были перемещены)

Обходной путь, который я использую, заключается в записи смещений вида после каждой операции перетаскивания и повторного применения их в onLayout() , например

 View mVdhView; int mVdhXOffset; int mVdhYOffset; @Override public void computeScroll() { if (dragHelper.continueSettling(true)) { postInvalidateOnAnimation(); } else { mVdhXOffset = mVdhView.getLeft(); mVdhYOffset = mVdhView.getTop(); } } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); // Reapply VDH offsets mVdhView.offsetLeftAndRight(mVdhXOffset); mVdhView.offsetTopAndBottom(mVdhYOffset); } 

Я столкнулся с той же проблемой при игре с DrawerLayout (макет с перетаскиваемыми ящиками), и изначально также был удивлен.

Из чтения источника кажется, что ViewDragHelper использует offsetLeftAndRight () / offsetTopAndBottom () для визуального перемещения любого захваченного и перетаскиваемого представления, предположительно для того, чтобы его можно было использовать до API 4.

Чтобы ответить на ваш вопрос : макет НЕ возится с позициями View, просто с помощью функций offset .. (), которые ViewDragHelper не мешает позиционированию View для вас.

Таким образом, в onLayout вашего представления вам придется учитывать любое визуальное позиционирование, сделанное с помощью ViewDragHelper. Например, в DrawerLayout это внутренне отслеживается через простое поле «lp.onScreen» и в onLayout () соответствующий сдвиг добавляется к параметрам при вызове child.layout () для любого перетаскиваемого дочернего представления ящика.

Этот ответ немного запоздалый, но причина, по которой ваш контент передается в исходное положение, когда вызывается requestLayout (), (по большей части), потому что ваш код в onLayout () не учитывает изменения в представлениях должность.

В примере flavienlaurent его код компоновки позиционирует перетаскиваемый вид в левой позиции 0, но верхняя позиция использует глобальную переменную mTop, которая модифицируется внутри обратного вызова onViewPositionChanged (android.view.View, int, int, int, int) На значение top. Вам нужно отслеживать значения вашего изменения и принимать их во внимание внутри onLayout ().

Простой способ сохранить изменения позиции в комплекте с видом перетаскивания – сохранить их внутри LayoutParams и получить тему внутри кода макета. Это особенно полезно, если вы хотите иметь несколько перетаскиваемых представлений внутри вашего макета. Отличным примером этого шаблона является исходный код Android SDK DrawerLayout (NavigationDrawer). Взгляните на нижнюю часть класса на собственный класс LayoutParams. Он имеет поле onScreen, которое является типом float. Эта переменная используется для хранения разницы в позиции (относительно исходного вида) перетаскиваемого представления и обновляется в setDrawerViewOffset ().

Еще один пример – сделать то, что рекомендовал пользователь @ user3452758, но снова будет сложно отслеживать, если вы когда-либо захотите иметь несколько перетаскиваемых представлений.

Извините, я не знаю, почему вызывается layout (), но, возможно, одно из ваших представлений, таких как ViewPager call getView (View parentView).

В любом случае, я предполагаю, что вы используете DragViewHelper, как этот блог . Таким образом, существует метод revelant OnLayoutChangeListener, который перемещает макет в предыдущую позицию.

MyActivity.java

 //parent rlOuterView = (SlidingLayout) findViewById(R.id.sl_sliding_view); //child - slides up/down rlAppBarFooter = (RelativeLayout) findViewById(R.id.rl_footer); rlMainView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { @Override public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { if( rlOuterView.isMoving() ){ v.setTop(oldTop); v.setBottom(oldBottom); v.setLeft(oldLeft); v.setRight(oldRight); } } }); 

Поэтому, когда вызывается layout (), метод isMoving должен быть запущен – но похоже, что нет. Поскольку DragViewHelper находится в STATE_IDLE. Я благодарю за трюк, чтобы ответить пользователем3452758. Вам нужно установить флаг в вашем настраиваемом скользящем макете в методе computeScroll (), который включит isMoving == true в нужное время.

SlidingLayout.java

 public class SlidingLayout extends RelativeLayout { /* ........... */ @Override public void computeScroll() { // needed for automatic settling. if (mDragHelper.continueSettling(true)) { ViewCompat.postInvalidateOnAnimation(this); preventPositionReset = false; }else{ preventPositionReset = true; } } public boolean isMoving() { return (/*mDraggingState == ViewDragHelper.STATE_IDLE ||*/ preventPositionReset || mDraggingState == ViewDragHelper.STATE_DRAGGING || mDraggingState == ViewDragHelper.STATE_SETTLING); } /* ......... */ }