web-dev-qa-db-ja.com

DrawerLayoutのアイテムクリック-フラグメントを置換する適切なタイミングはいつですか?

ナビゲーションドロワーパターン(With DrawerLayout)を使用するアプリケーションを開発しています。

引き出しのアイテムをクリックするたびに、メインコンテナのフラグメントが置き換えられます。

ただし、いつフラグメントトランザクションを実行するのが適切かはわかりません。引き出しが閉じ始めると?それとも閉じた後?

Googleの ドキュメントの例 では、アイテムをクリックした直後にトランザクションを実行していることがわかり、引き出しを閉じます。
その結果、引き出しが遅れて滑らかでなく、非常に悪く見えます(私のアプリケーションでも起こります)。

Gmail および Google Drive アプリケーションでは、逆に、ドロワーが閉じた後にトランザクションを実行しているようです(そうですか?)。
その結果、ドロワーは遅延がなく、非常に滑らかではありませんが、次のフラグメントを見るには少なくとも約1秒かかります(ドロワーが閉じるのにかかる時間)。

すぐにフラグメントトランザクションを行う場合、ドロワーがスムーズになる方法はないようです。

あれについてどう思う?

前もって感謝します!

46
dor506

うん、同意できませんでした。フラグメント(ビュー付き)トランザクションを実行すると、DrawerLayoutdocs を引用して、アニメーション化されたビューでジャンキーアニメーションを引き起こすレイアウトパスが発生します。

DrawerLayout.DrawerListenerを使用して、ドロワービューの状態と動きを監視できます。アニメーション中にレイアウトなどの高価な操作を実行すると、音が途切れることがあります。 STATE_IDLE状態の間に高価な操作を実行してみてください。

引き出しを閉じた後、または誰かが何らかの形でそれを修正するためにサポートライブラリにパッチを適用した後、フラグメントトランザクションを実行してください:)

24
eveliotc

別の解決策は、次のように、引き出しを閉じた後にHandlerを作成し、遅延Runnableを投稿することです。 https://stackoverflow.com/a/18483633/769501 。このアプローチの利点は、フラグメントがDrawerListener#onDrawerClosed()を待っている場合よりもはるかに早く置き換えられることですが、もちろん、任意の遅延は、引き出しアニメーションが時間内に終了することを100%保証するものではありません。

とは言っても、200msの遅延を使用すると、うまく機能します。

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);
    }
}
25
Makario

これは、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;
         }
     }
 }

それがあなたを助けることを願っています! :-)

15
saguinav

私はこの質問が古いことを知っていますが、同じ問題にぶつかり、ハードコードされた遅延時間を追加するよりも優れた実装だと思うので、ソリューションを投稿すると思いました。私がしたことは、onDrawerClosed関数を使用して、タスクを実行する前に引き出しISが閉じていることを確認することでした。

//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
user1282637

ハンドラーでコードを記述し、200ミリ秒の遅延をかけるだけです。

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

アイテムのクリックを遅らせる代わりに、アプリの動作が遅くなる可能性があります。私はmDrawerLayoutのクローズを遅らせるだけです。これらのコールバックは非常に遅いため、DrawerLayout.OnDrawerListener onClose(...)も使用しません。

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

スムーズに遅滞なく使用する場合は、ドロワーを開いたままにし、戻ったときに(onRestart()メソッドで)閉じます。

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

副作用は、戻ったときの(スピーディな)アニメーションですが、これは許容範囲です。

0
Nesreteip