Подтвердить что ты не робот

DrawerLayout item click - Когда подходящее время для замены фрагмента?

Я разрабатываю приложение, которое использует шаблон ящика навигации (с DrawerLayout).

Каждый щелчок по элементу ящика заменяет фрагмент в основном контейнере.

Однако, я не уверен, когда настало время сделать транзакцию фрагмента? Когда ящик начинает закрываться? Или после его закрытия?

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

В Gmail и Google Диске, с другой стороны, похоже, что они делают транзакция после закрытия ящика (я прав?).
В результате ящик не лагги и очень плавный, НО требуется, по крайней мере, 1 секунда (время, необходимое для закрытия ящика), чтобы увидеть следующий фрагмент.

Похоже, что ящик не будет гладким, если вы сразу сделаете транзакцию фрагмента.

Что вы думаете об этом?

Спасибо заранее!

4b9b3361

Ответ 1

Yup, не мог согласиться больше, выполнение транзакции с фрагментом (с представлением) приводит к переходу макета, который вызывает анимированные анимации анимации, цитируя DrawerLayout docs:

DrawerLayout.DrawerListener может использоваться для контроля состояния и движения представлений ящика. Избегайте выполнения дорогостоящих операций, таких как макет во время анимации, поскольку это может вызвать заикание; попробуйте выполнить дорогостоящие операции в состоянии STATE_IDLE.

Итак, пожалуйста, выполните транзакции фрагмента после закрытия ящика, или кто-то исправляет библиотеку поддержки, чтобы как-то исправить это:)

Ответ 2

Еще одно решение - создать Handler и отправить задержку Runnable после закрытия ящика, как показано ниже: fooobar.com/questions/108627/.... Преимущество такого подхода заключается в том, что ваши фрагменты будут заменены гораздо раньше, чем они были бы, если бы вы ждали DrawerListener#onDrawerClosed(), но, конечно, произвольная задержка не гарантирует 100% анимацию ящика со временем.

Тем не менее, я использую задержку в 200 мс и прекрасно работает.

private class DrawerItemClickListener implements OnItemClickListener {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, final int position, long id) {
        drawerLayout.closeDrawer(drawerList);
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                switchFragments(position); // your fragment transactions go here
            }
        }, 200);
    }
}

Ответ 3

Это то, что я делаю, чтобы добиться плавной анимации транзакций, похожей на приложение Gmail:

activity_drawer.xml

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <!-- The main content view -->
    <FrameLayout
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <!-- The navigation drawer -->
    <ListView 
    android:id="@+id/left_drawer"
        android:layout_width="280dp"
        android:layout_height="match_parent"
        android:layout_gravity="left"
        android:choiceMode="singleChoice" />

</android.support.v4.widget.DrawerLayout>

DrawerActivity.java

private Fragment mContentFragment;
private Fragment mNextContentFragment;
private boolean mChangeContentFragment = false;

private Handler mHandler = new Handler();

...

@Override
public void onCreate(Bundle savedInstanceState) {
    ...

    mDrawerLayout.setDrawerListener(new DrawerListener());

    mDrawerList.setOnItemClickListener(new DrawerItemClickListener());

    ...
}

....

private class DrawerItemClickListener implements ListView.OnItemClickListener {

    @Override
    public void onItemClick(AdapterView parent, View view, int position, long id) {
        getSupportFragmentManager().beginTransaction().remove(mContentFragment).commit();

        switch (position) {
            case 0:
                mNextContentFragment = new Fragment1();
                break;

            case 1:
                mNextContentFragment = new Fragment2();
                break;

            case 2:
                mNextContentFragment = new Fragment3();
                break;
        }

        mChangeContentFragment = true;

        mDrawerList.setItemChecked(position, true);

        mHandler.postDelayed(new Runnable() {

            @Override
            public void run() {
                mDrawerLayout.closeDrawer(mDrawerList);
            }           
        }, 150);
    }
}

private class DrawerListener implements android.support.v4.widget.DrawerLayout.DrawerListener {

    @Override
    public void onDrawerClosed(View view) {
        if (mChangeContentFragment) {
             getSupportFragmentManager().beginTransaction().setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN).replace(R.id.content_frame, mNextContentFragment).commit();

             mContentFragment = mNextContentFragment;           
             mNextContentFragment = null;

             mChangeContentFragment = false;
         }
     }
 }

Надеюсь, что тебе поможет!:-)

Ответ 4

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

//on button click...
private void displayView(int position) {
    switch (position) {
    //if item 1 is selected, update a global variable `"int itemPosition"` to be 1
    case 1:
        itemPosition = 1;
        //();
        break;
    default:
        break;
    }

    // update selected item and title, then close the drawer
    mDrawerList.setItemChecked(position, true);
    mDrawerList.setSelection(position);
    mDrawerLayout.closeDrawer(mDrawerList); //close drawer
}

а затем в onDrawerClosed откройте соответствующую операцию.

public void onDrawerClosed(View view) {
    getSupportActionBar().setTitle(mTitle);
    // calling onPrepareOptionsMenu() to show action bar icons
    supportInvalidateOptionsMenu();
    if (itemPosition == 1) {
        Intent intent = new Intent(BaseActivity.this, SecondActivity.class);
        startActivity(intent);
    }
}

Ответ 5

Просто напишите свой код в обработчике и поставьте задержку 200 мс.

 new Handler().postDelayed(new Runnable() {
  @Override
   public void run() {
       openSelectionDrawerItem(position);          
   }
 }, 200);

Ответ 6

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

new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
        mDrawerLayout.closeDrawer(GravityCompat.START);
    }
}, 200);

Ответ 7

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

@Override
protected void onRestart() {
    // TODO Auto-generated method stub
    super.onRestart();
    mDrawerLayout.closeDrawer(mDrawerList);     
}

Побочный эффект - это (быстрая) анимация при возврате, но это может быть приемлемо.