当前位置: 首页 > 知识库问答 >
问题:

关闭时加快“导航抽屉”动画速度?

松昱
2023-03-14

按预期实现和工作,因此确实没有代码值得在这里发布,只是想看看是否有人有加快抽屉打开和关闭时间的经验?例如,YouTube应用程序要快得多!

共有3个答案

艾才良
2023-03-14

首先从下面的链接下载源代码文件

抽屉布局。Java语言

ViewDrawerHelper。Javahtml" target="_blank">语言

然后将以上两个文件粘贴到你的应用程序util包中(或你想要的地方),并在你的活动中参考这个抽屉布局,而不是android。支持v4.widget。抽屉布局更改活动布局文件中的抽屉布局参考,

现在调整一下

private static final int MAX_SETTLE_DURATION = 600; // ms

对于ViewDrawerHelper,加速只需增加值,而下降只需减少值。

如果您想在操作栏切换按钮上添加操作,请从下面的链接下载以下源文件

ActionBarDrawerToggle。Java语言

JellyBeanMR2.java

切换oneycomb.java

并将上述文件粘贴到您的应用程序util包(或您想要的地方)注意:-确保每个新添加文件的导入包都指向应用程序项目中的文件,而不是android的文件。支持控件。*;

如果以上链接不起作用,请添加http://

缪嘉志
2023-03-14

加速动画并等待它完成的另一种选择是首先简单地避免动画:只需调用start Active()而不调用CloseDrawer()。虽然您没有看到抽屉关闭,但活动转换动画仍然提供了相当不错的效果,并且它立即发生,无需等待抽屉关闭动画先完成沉淀,没有波动性,并且感知延迟要短得多。

(如果您只想查看代码,可以跳过此解释。)

要实现这一点,您需要一种方法,在使用“后退”按钮导航回活动时,在没有任何关闭动画的情况下关闭抽屉。(不调用closeDrawer()将使该活动实例中的抽屉保持打开状态;一种相对浪费的解决方法是在返回时强制活动重新创建(),但不这样做也可以解决这个问题。)您还需要确保只有在导航后返回时才关闭抽屉,而不是在方向更改后,但这很容易。

虽然从onCreate()调用closeDrawer()将使抽屉在没有任何动画的情况下开始关闭,但从onResume()调用时情况并非如此。从onResume()调用closeDrawer()将以用户瞬间可见的动画关闭抽屉<代码>抽屉布局(code>DrawerLayout)不提供任何方法来关闭没有该动画的抽屉,但可以添加一个。

正如@syesilova所指出的,关闭抽屉实际上只是把它从屏幕上滑下来。因此,通过将抽屉直接移动到其“关闭”位置,可以有效跳过动画。平移方向将根据重力而变化(无论是左抽屉还是右抽屉),准确位置取决于抽屉及其所有子抽屉的大小。

然而,仅仅移动它是不够的,因为DrawerLayout在扩展的LayoutParams中保留了一些内部状态,用于了解抽屉是否打开。如果您只是将抽屉移出屏幕,它将不知道它已关闭,这将导致其他问题。(例如,抽屉将在下一次方向更改时重新出现。)

由于您正在将支持库编译到应用程序中,因此可以在android中创建一个类。支持小部件包,以访问其默认(包私有)部分,或扩展抽屉布局,而无需复制其所需的任何其他类。这还将减少在将来更改支持库时更新代码的负担。(最好尽可能将代码与实现细节隔离开来。)您可以使用moveDrawerToOffset()移动抽屉,并设置布局参数,使其知道抽屉已关闭。

这是跳过动画的代码:

// 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,则抽屉将在下一次方向更改时移回其打开位置。

这种方法向支持中添加了一个实用程序类。v4软件包,以获取我们在抽屉布局内需要的软件包私有部分。

将此类放入/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()方法在无动画的情况下关闭抽屉:

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

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

这种方法扩展了DrawerLayout以添加setDrawerCloked()方法。

将此类放入/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);
        /**/
    }
}

在活动布局中使用自定义抽屉布局,而不是使用抽屉布局:

<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()方法在无动画的情况下关闭抽屉:

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

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

我发现这是避免起伏的最好方法,没有任何长时间的感知延迟。

您几乎可以使用类似的技术来模拟在到达活动后关闭抽屉,方法是在意图中传递一个值,告诉新活动在没有动画的情况下从onCreate()打开抽屉,然后在活动布局完成后为其关闭设置动画,但是在我的实验中,活动转换破坏了模拟的效果,所以你也需要禁用它。

通迪
2023-03-14

您当然可以调整动画的持续时间,但这需要您从支持库中复制类,然后相应地编辑它们。

ViewDragHelper视图

持续时间在ViewDragHelper中确定

然后,当ViewDragHelper时,应用于抽屉布局。调用SmoothSlideViewWTO

您需要创建ViewDragHelper的修改版本。forceSettleCapturedViewAt,在持续时间参数中传递。

forceSettleCapturedViewAt(... int duration)

然后创建您的ViewDragHelper版本。SmoothSlideViewWTO。

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

抽屉布局

接下来,您需要修改抽屉布局。关闭抽屉和抽屉布局。衣柜以匹配新的ViewDragHelper修改。

ActionBarDrawerToggle

您还必须复制ActionBarDrawertogleActionBarDrawertogleHoneycomb。不过,这些文件不需要任何编辑。

 类似资料:
  • 我尝试在我的应用程序中实现导航抽屉(材料设计)。我的活动包含带有片段的FrameLayout。当用户在导航抽屉FrameLayout中选择项目时,重新加载新片段: 当我点击项目时,一切正常。导航抽屉关闭不顺利,但冻结(抽搐,抽搐),因为片段在后台重新加载。 如何顺利关闭导航抽屉?

  • 我是android新手。我有一个关于Android导航抽屉的问题。我在我的应用程序中加入了导航抽屉,一切都很顺利,但我想知道是否有人能帮我在导航抽屉列表中获得惰性动画。 图像的来源。 非常感谢。

  • 在我的片段中,我通过编程将片段添加到导航抽屉中,然后从右侧打开抽屉。注意,我无法直接访问抽屉布局的xml文件,因此需要一个编程解决方案。抽屉从右侧打开并正确关闭,我保留抽屉的打开/关闭状态,并在配置根据该状态更改后打开它。 问题是,在配置更改时,抽屉关闭(我可以看到抽屉动画到关闭状态),即使我根据保存的InstanceState布尔值恢复其打开/关闭状态。我在中的所有方法中放置了调试器,但它们没有

  • 我的应用程序有一个导航抽屉。从抽屉选项,我正在打开不同的活动。此时,在新活动之前显示一个空白屏幕。

  • 二等 三等

  • 每当用户按下< code >底部导航栏中的一个按钮时,我都想关闭我的< code >抽屉小部件,但是我不太明白这一点。我现在设置BNB的方式是通过应用程序记住所有屏幕的当前状态(使用< code>IndexedStack),但我想在按下BNB按钮之前关闭任何屏幕中打开的抽屉。我的每个屏幕都有自己的抽屉和应用程序栏,所以我不能在BNB里面放一个抽屉(或者我可以,我可以用一个开关盒动态地改变它们,当一