17

実装され、期待どおりに動作するため、ここに投稿する価値のあるコードは実際にはありません。単に引き出しの開閉にかかる時間を短縮した経験があるかどうかを調べてみてください。たとえば、YouTube アプリははるかに高速です。

4

7 に答える 7

24

アニメーションの長さは間違いなく調整できますが、サポート ライブラリからクラスをコピーして、それに応じて編集する必要があります。

ViewDragHelper

期間はここで決定されますViewDragHelper

次に、呼び出さDrawerLayoutれたときに適用されますViewDragHelper.smoothSlideViewTo

ViewDragHelper.forceSettleCapturedViewAt期間パラメーターで渡される変更されたバージョンを作成する必要があります。

forceSettleCapturedViewAt(... int duration)

次に、バージョンの を作成しますViewDragHelper.smoothSlideViewTo

public boolean smoothSlideViewTo(... int duration) {
        ...
        return forceSettleCapturedViewAt(... int duration);
    }

ドロワーレイアウト

DrawerLayout.closeDrawer次に、変更しDrawerLayout.closeDrawersて、新しい変更に一致させる必要がありますViewDragHelper

ActionBarDrawerToggle

と もコピーする必要がActionBarDrawerToggleありActionBarDrawerToggleHoneycombます。ただし、これらのファイルを編集する必要はありません。

于 2013-10-19T01:09:18.560 に答える
7

アニメーションを高速化して終了を待つ代わりに、最初からアニメーションを回避することもできます: を呼び出さstartActivity()ずに呼び出すだけcloseDrawer()です。ドロワーが閉じている様子は見えませんが、アクティビティの遷移アニメーションは非常に優れた効果を提供し、すぐに発生します。ドロワーを閉じるアニメーションが最初に落ち着くのを待つ必要はなく、ぎこちなく、知覚的な遅延がはるかに短くなります。 .


詳細

(コードだけを見たい場合は、この説明をスキップできます。)

これを機能させるには、戻るボタンでアクティビティに戻るときに、閉じるアニメーションなしでドロワーを閉じる方法が必要です。(呼び出さないとcloseDrawer()、そのアクティビティ インスタンスで引き出しが開いたままになります。比較的無駄な回避策は、recreate()戻るときにアクティビティを強制することですが、それを行わなくてもこれを解決することは可能です。)方向の変更後ではなく、移動後に戻る場合は引き出しですが、それは簡単です。

closeDrawer()fromを呼び出すとonCreate()、アニメーションなしでドロワーが閉じられますが、 from からは同じではありませんonResume()closeDrawer()から呼び出すonResume()と、ユーザーに一時的に表示されるアニメーションでドロワーが閉じられます。DrawerLayoutそのアニメーションなしで引き出しを閉じる方法はありませんが、追加することは可能です。

@syesilova が指摘しているように、引き出しを閉じると、実際には画面からスライドするだけです。そのため、ドロワーを「閉じた」位置に直接移動することで、アニメーションを効果的にスキップできます。平行移動の方向は重力 (引き出しが左か右か) によって異なり、正確な位置は、すべての子を配置した後の引き出しのサイズによって異なります。

ただし、ドロワーが開いているかどうかを知るために使用するDrawerLayout内部状態を拡張して保持するため、単に移動するだけでは十分ではありません。LayoutParamsドロワーを画面外に移動すると、ドロワーが閉じていることを認識できず、別の問題が発生します。(たとえば、引き出しは次の向きの変更で再表示されます。)

サポート ライブラリをアプリにコンパイルしているので、android.support.v4.widgetパッケージ内にクラスを作成して、その既定の (パッケージ プライベート) パーツにアクセスしたり、DrawerLayout必要な他のクラスをコピーせずに拡張したりできます。これにより、サポート ライブラリへの将来の変更に合わせてコードを更新する負担も軽減されます。(可能な限り実装の詳細からコードを隔離することが常に最善です。) を使用moveDrawerToOffset()してドロワーを移動し、 を設定しLayoutParamsて、ドロワーが閉じていることを認識できるようにします。


コード

アニメーションをスキップするコードは次のとおりです。

// move drawer directly to the closed position
moveDrawerToOffset(drawerView, 0.f); 

/* EDIT: as of v23.2.1 this direct approach no longer works
         because the LayoutParam fields have been made private...
// set internal state so DrawerLayout knows it's closed
final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
lp.onScreen = 0.f;
lp.knownOpen = false;

invalidate();
/*/
// ...however, calling closeDrawer will set those LayoutParams
//    and invalidate the view.
closeDrawer(drawerView);
/**/

注:moveDrawerToOffset()を変更せずに呼び出すとLayoutParams、次の方向変更時に引き出しが開いた位置に戻ります。


オプション 1 (既存の DrawerLayout を使用)

このアプローチは、ユーティリティ クラスを support.v4 パッケージに追加して、DrawerLayout 内で必要なパッケージ プライベート パーツにアクセスできるようにします。

このクラスを /src/android/support/v4/widget/ に配置します。

package android.support.v4.widget;

import android.support.annotation.IntDef;
import android.support.v4.view.GravityCompat;
import android.view.Gravity;
import android.view.View;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

public class Support4Widget {

    /** @hide */
    @IntDef({Gravity.LEFT, Gravity.RIGHT, GravityCompat.START, GravityCompat.END})
    @Retention(RetentionPolicy.SOURCE)
    private @interface EdgeGravity {}

    public static void setDrawerClosed(DrawerLayout drawerLayout, @EdgeGravity int gravity) {
        final View drawerView = drawerLayout.findDrawerWithGravity(gravity);
        if (drawerView == null) {
            throw new IllegalArgumentException("No drawer view found with gravity " +
                    DrawerLayout.gravityToString(gravity));
        }

        // move drawer directly to the closed position
        drawerLayout.moveDrawerToOffset(drawerView, 0.f); 
        
        /* EDIT: as of v23.2.1 this no longer works because the
                 LayoutParam fields have been made private, but
                 calling closeDrawer will achieve the same result.
        
        // set internal state so DrawerLayout knows it's closed
        final DrawerLayout.LayoutParams lp = (DrawerLayout.LayoutParams) drawerView.getLayoutParams();
        lp.onScreen = 0.f;
        lp.knownOpen = false;

        drawerLayout.invalidate();
        /*/
        // Calling closeDrawer updates the internal state so DrawerLayout knows it's closed
        // and invalidates the view for us.
        drawerLayout.closeDrawer(drawerView);
        /**/
    }
}

移動するときにアクティビティにブール値を設定し、ドロワーを閉じる必要があることを示します。

public static final String CLOSE_NAV_DRAWER = "CLOSE_NAV_DRAWER";
private boolean mCloseNavDrawer;

@Override
public void onCreate(Bundle savedInstanceState) {
    // ...
    if (savedInstanceState != null) {
        mCloseNavDrawer = savedInstanceState.getBoolean(CLOSE_NAV_DRAWER);
    }
}

@Override
public boolean onNavigationItemSelected(MenuItem menuItem) {

    // ...

    startActivity(intent);
    mCloseNavDrawer = true;
}

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    savedInstanceState.putBoolean(CLOSE_NAV_DRAWER, mCloseNavDrawer);
    super.onSaveInstanceState(savedInstanceState);
}   

...メソッドを使用して、アニメーションなしsetDrawerClosed()で引き出しを閉じます。onResume()

@Overrid6e
protected void onResume() {
    super.onResume();

    if(mCloseNavDrawer && mDrawerLayout != null && mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
        Support4Widget.setDrawerClosed(mDrawerLayout, GravityCompat.START);
        mCloseNavDrawer = false;
    }
}

オプション 2 (DrawerLayout から拡張)

このアプローチは DrawerLayout を拡張して setDrawerClosed() メソッドを追加します。

このクラスを /src/android/support/v4/widget/ に配置します。

package android.support.v4.widget;

import android.content.Context;
import android.support.annotation.IntDef;
import android.support.v4.view.GravityCompat;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

public class CustomDrawerLayout extends DrawerLayout {

    /** @hide */
    @IntDef({Gravity.LEFT, Gravity.RIGHT, GravityCompat.START, GravityCompat.END})
    @Retention(RetentionPolicy.SOURCE)
    private @interface EdgeGravity {}
    
    public CustomDrawerLayout(Context context) {
        super(context);
    }

    public CustomDrawerLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomDrawerLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }
    
    public void setDrawerClosed(View drawerView) {
        if (!isDrawerView(drawerView)) {
            throw new IllegalArgumentException("View " + drawerView + " is not a sliding drawer");
        }
        
        // move drawer directly to the closed position
        moveDrawerToOffset(drawerView, 0.f); 
        
        /* EDIT: as of v23.2.1 this no longer works because the
                 LayoutParam fields have been made private, but
                 calling closeDrawer will achieve the same result.
        
        // set internal state so DrawerLayout knows it's closed
        final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
        lp.onScreen = 0.f;
        lp.knownOpen = false;
        
        invalidate();
        /*/
        // Calling closeDrawer updates the internal state so DrawerLayout knows it's closed
        // and invalidates the view for us.
        closeDrawer(drawerView);
        /**/
    }

    public void setDrawerClosed(@EdgeGravity int gravity) {
        final View drawerView = findDrawerWithGravity(gravity);
        if (drawerView == null) {
            throw new IllegalArgumentException("No drawer view found with gravity " +
                    gravityToString(gravity));
        }

        // move drawer directly to the closed position
        moveDrawerToOffset(drawerView, 0.f); 
        
        /* EDIT: as of v23.2.1 this no longer works because the
                 LayoutParam fields have been made private, but
                 calling closeDrawer will achieve the same result.
        
        // set internal state so DrawerLayout knows it's closed
        final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
        lp.onScreen = 0.f;
        lp.knownOpen = false;

        invalidate();
        /*/
        // Calling closeDrawer updates the internal state so DrawerLayout knows it's closed
        // and invalidates the view for us.
        closeDrawer(drawerView);
        /**/
    }
}

CustomDrawerLayoutアクティビティ レイアウトの代わりに使用DrawerLayoutします。

<android.support.v4.widget.CustomDrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    >

...移動するときにアクティビティにブール値を設定し、ドロワーを閉じる必要があることを示します。

public static final String CLOSE_NAV_DRAWER = "CLOSE_NAV_DRAWER";
private boolean mCloseNavDrawer;

@Override
public void onCreate(Bundle savedInstanceState) {
    // ...
    if (savedInstanceState != null) {
        mCloseNavDrawer = savedInstanceState.getBoolean(CLOSE_NAV_DRAWER);
    }
}

@Override
public boolean onNavigationItemSelected(MenuItem menuItem) {

    // ...

    startActivity(intent);
    mCloseNavDrawer = true;
}

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    savedInstanceState.putBoolean(CLOSE_NAV_DRAWER, mCloseNavDrawer);
    super.onSaveInstanceState(savedInstanceState);
}   

...メソッドを使用して、アニメーションなしsetDrawerClosed()で引き出しを閉じます。onResume()

@Overrid6e
protected void onResume() {
    super.onResume();

    if(mCloseNavDrawer && mDrawerLayout != null && mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
        mDrawerLayout.setDrawerClosed(GravityCompat.START);
        mCloseNavDrawer = false;
    }
}

これは、長い知覚的遅延なしに途切れを避けるための最良の方法であることがわかりました.

同様の手法を使用して、アクティビティに到着した後にドロワーを閉じることをシミュレートできます。インテントに値を渡して、新しいアクティビティにアニメーションなしでドロワーを開くように指示しonCreate()、アクティビティのレイアウトが終了した後にドロワーを閉じるようにアニメーション化します。ただし、私の実験では、アクティビティの遷移によってシミュレーションの効果が損なわれたため、それを無効にする必要もあります。

于 2015-07-15T01:22:27.503 に答える
2

まず、以下のリンクからソースコード ファイルをダウンロードします。

DrawerLayout.java

ViewDrawerHelper.java

上記の 2 つのファイルをアプリケーションの util パッケージ (または必要な場所)に貼り付け、android.support.v4.widget.DrawerLayout ではなくアクティビティでこのドロワー レイアウトを参照します。アクティビティのレイアウト ファイルでドロワー レイアウトの参照を変更します。

今すぐ調整

private static final int MAX_SETTLE_DURATION = 600; // ms

ViewDrawerHelperの値を増やすだけでスピードアップし、値を減らすだけでダウンします。

アクション バーのトグル ボタンにアクションを追加する場合は、以下のリンクから のソース ファイルをダウンロードします。

ActionBarDrawerToggle.java

ActionBarDrawerToggleJellybeanMR2.java

ActionBarDrawerToggleHoneycomb.java

上記のファイルをアプリケーション util パッケージ (または必要な場所) に貼り付けます。注:- 新しく追加された各ファイルのインポートされたパッケージが、android.support.v4.widget ではなく、アプリケーション プロジェクトにあるファイルを参照していることを確認してください。 *;

上記のリンクが機能しない場合は、http:// を追加してください

于 2014-10-03T08:22:22.557 に答える
2

アニメーションの速度を変更することはできませんが、引き出しをすぐに閉じたい場合DrawerLayout.closeDrawer(int/View, bool)は、サポート ライブラリの v24 の新しいメソッドを使用できます。

drawerLayout.closeDrawer(Gravity.LEFT, false);
于 2016-06-28T01:36:42.090 に答える
1

アニメーションなしで左側のパネルをすぐに強制的に消したい場合は、x 値を設定するだけです。ドロワー レイアウトを開くと左パネルの x 値は 0 になり、閉じると -1*(その幅) になります。したがって、開いているときに x 値 -2*幅 を設定すると、左パネルはすぐに消えます。そしてもちろん、閉じた後に x を -1*width に設定することを忘れないでください。例えば:

DisplayMetrics metrics = new DisplayMetrics();
this.getWindowManager().getDefaultDisplay().getMetrics(metrics);
//obtain left panel's width in px
private float mToggleStartX=-260*metrics.density; //260 is the width of left panel in dpi

//while drawer layout is opened, to disappear left panel
ll_drawerLayoutMenuPanel.setX(mToggleStartX*2); //ll_drawerLayoutMenuPanel is the left panel layout
mDrawerLayout.closeDrawers();

//don't forget reset x value in the onDrawerClosed method.
mDrawerToggle = new ActionBarDrawerToggle(this,mDrawerLayout,mainToolBar,R.string.drawer_open,R.string.drawer_close) {
    public void onDrawerClosed(View view) {
        super.onDrawerClosed(view);

        ll_drawerLayoutMenuPanel.setX(mToggleStartX);
    }
    ......
};
于 2015-02-15T13:05:59.117 に答える