Ускорить скорость анимации «Навигационный ящик» при закрытии?

Реализованный и работающий, как и ожидалось, как таковой действительно не существует кода, который стоит опубликовать здесь, просто глядя, чтобы узнать, есть ли у кого-нибудь опыт ускорения времени, которое требуется, чтобы ящик открывался и закрывался? Например, приложение YouTube намного быстрее!

Вы можете точно настроить продолжительность анимации, но вам потребуется скопировать classы из библиотеки поддержки, а затем отредактировать их соответствующим образом.

ViewDragHelper

Продолжительность определяется здесь в ViewDragHelper

Затем применяется к DrawerLayout при ViewDragHelper.smoothSlideViewTo

Вам нужно будет создать измененную версию ViewDragHelper.forceSettleCapturedViewAt которая проходит в параметре длительности.

 forceSettleCapturedViewAt(... int duration) 

Затем создайте свою версию ViewDragHelper.smoothSlideViewTo .

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

DrawerLayout

Затем вам нужно будет изменить DrawerLayout.closeDrawer и DrawerLayout.closeDrawers чтобы они соответствовали вашим новым модификациям ViewDragHelper .

ActionBarDrawerToggle

Вам также придется копировать ActionBarDrawerToggle и ActionBarDrawerToggleHoneycomb . Однако эти файлы не требуют редактирования.

Альтернативой ускорению анимации и ожиданием ее завершения является просто исключить анимацию в первую очередь: просто вызовите startActivity() не вызывая closeDrawer() . Хотя вы не видите, что ящик закрыт, анимация перехода к действию по-прежнему обеспечивает довольно приятный эффект, и это происходит немедленно, без необходимости ждать, пока анимация закрывает ящик, чтобы завершить настройку сначала, без прерывания и более короткую задержку восприятия ,


Детали

(Вы можете пропустить это объяснение, если хотите просто посмотреть код.)

Чтобы выполнить эту работу, вам понадобится способ закрыть ящик без какой-либо близкой анимации при навигации назад к активности с помощью кнопки «Назад». (Не вызывая closeDrawer() вы откроете ящик в этом экземпляре активности, относительно расточительным обходным путем будет просто принудительно closeDrawer() активность для recreate() при навигации по назад, но это можно решить, не делая этого.) Вам также необходимо убедитесь, что вы только закрываете ящик, если вы возвращаетесь после навигации, а не после изменения ориентации, но это легко.

Хотя вызов функции closeDrawer() из onCreate() приведет к тому, что ящик начнет закрываться без какой-либо анимации, то это же неверно из onResume() . Вызов функции closeDrawer() из onResume() закроет ящик с анимацией, которая мгновенно отображается пользователю. DrawerLayout не предоставляет никакого способа закрыть ящик без этой анимации, но его можно добавить.

Как отмечает @syesilova, закрытие ящика фактически просто снимает его с экрана. Таким образом, вы можете эффективно пропускать анимацию, перемещая ящик непосредственно в «закрытую» позицию. Направление перевода будет варьироваться в зависимости от силы тяжести (будь то левый или правый ящик), и точное положение зависит от размера выдвижного ящика, когда оно выложено всеми его детьми.

Однако просто перемещать его недостаточно, поскольку DrawerLayout сохраняет некоторое внутреннее состояние в расширенных LayoutParams которое оно использует, чтобы узнать, открыт ли ящик. Если вы просто переместите ящик с экрана, он не будет знать, что он закрыт, и это вызовет другие проблемы. (Например, ящик снова появится при следующем изменении ориентации.)

Поскольку вы компилируете библиотеку поддержки в свое приложение, вы можете создать class в пакете android.support.v4.widget , чтобы получить доступ к его частям по умолчанию (для пакета), или расширить DrawerLayout без копирования через любой другой classов, которые ему нужны. Это также уменьшит нагрузку на обновление кода с будущими изменениями в библиотеке поддержки. (Всегда лучше изолировать свой код от деталей реализации как можно больше.) Вы можете использовать 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)

Этот подход добавляет class утилиты в пакет support.v4, чтобы получить доступ к частным частям пакета, которые нам нужны внутри DrawerLayout.

Поместите этот class в / 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 ().

Поместите этот class в / 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 в ваших макетах действий:

  

… и установите логическое значение в вашей деятельности, когда вы перемещаетесь, указав, что ящик должен быть закрыт:

 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() а затем оживить его после макета активности закончен, однако в моих экспериментах переход активности разрушил эффект моделирования, поэтому вам также необходимо отключить его.

Сначала снизу ссылки загружают файлы sourcode

DrawerLayout.java

А также

ViewDrawerHelper.java

и вставьте эти два файла в свои приложения, используя пакет (или где вы хотите), и возьмите ссылку на этот макет ящика в своей деятельности, а не на android.support.v4.widget.DrawerLayout измените ссылку макета ящика в файле макета деятельности,

Теперь настройте

 private static final int MAX_SETTLE_DURATION = 600; // ms 

из ViewDrawerHelper, чтобы ускорить просто увеличить значение, а вниз – просто уменьшить значение.

Если вы хотите добавить действие на кнопку переключения панели действий, то из нижних ссылок загрузите исходные файлы

ActionBarDrawerToggle.java

ActionBarDrawerToggleJellybeanMR2.java

ActionBarDrawerToggleHoneycomb.java

и вставьте вышеуказанные файлы в свои приложения, используя пакет (или где вы хотите). Примечание. – Убедитесь, что импортированные пакеты каждого вновь добавленного файла относятся к файлу, который находится в вашем проекте приложения, а не к android.support.v4.widget. *;

если вышеуказанные ссылки не работают, добавьте http: //

Если вы хотите принудительно немедленно удалить левую панель без какой-либо анимации, вы можете просто установить ее значение x. Когда раскладка лотка открыта, значение ее левой панели x становится равным 0, а при закрытии становится -1 * (его ширина). Поэтому, если вы устанавливаете x значение -2 * width при его открытии, левая панель сразу же исчезает. И, конечно же, не забудьте установить x на -1 * ширину после ее закрытия. Например:

 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); } ...... }; 

Это не позволяет вам изменять скорость анимации, но если вы хотите только мгновенно закрыть ящик, вы можете использовать новые DrawerLayout.closeDrawer(int/View, bool) в v24 библиотеки поддержки:

 drawerLayout.closeDrawer(Gravity.LEFT, false); 

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

 mLeftDrawer.ItemClick += delegate (object sender, Android.Widget.AdapterView.ItemClickEventArgs e) { // Mark that item is selected and ask redraw e.View.Selected = true; adapter.NotifyDataSetChanged(); var handler = new Handler(); handler.PostDelayed(new Java.Lang.Runnable(() => { _mLeftDrawerLayout.CloseDrawers(); // Here you should call your activity }), 100); }; 

Закройте ящик после некоторой задержки согласно следующему

 @Override public boolean onNavigationItemSelected(MenuItem item) { // Handle navigation view item clicks here. yourFunction(); Handler handler = new Handler(); handler.postDelayed(new Runnable() { @Override public void run() { drawer.closeDrawer(GravityCompat.START); } }, 100); return true; } 
  • Межстраничные объявления Admob: «IllegalStateException: только действия в полноэкранном режиме могут запрашивать ориентацию»
  • URI из Intent.ACTION_GET_CONTENT в файл
  • Базовая реализация Android GCM
  • Android: что выбрать для значений кода запроса?
  • spannable на android для textView
  • Очистить задний стек с помощью fragmentов
  • Как обрабатывать сообщения обработчика, когда действие / fragment приостановлено
  • Как показать тост в AsyncTask в doInBackground
  • Почему onDraw не вызывается после invalidate ()?
  • Не удалось найти цель с хеш-строкой 'android-25'
  • Обновление библиотеки Google Play и отсутствующий символ @ integer / google_play_services_version
  • Давайте будем гением компьютера.