Как уменьшить фоновую активность при открытии панели навигации?

Я хочу сделать свой фон Activity немного меньше при открытии Navigation Drawer. Смоделируйте эффект, существующий в приложении Airbnb. Думаю, лучшим объяснением будет скриншот:

введите здесь описание изображения

Но дело не в том, чтобы просто уменьшить вид, а в том, чтобы сделать его анимацией, синхронизированной с анимацией открытия/закрытия ящика. Поэтому, если вы начали открывать ящик, а посередине решили остановиться и вернуться назад, это соответственно повлияет на шкалу фоновой активности.

Как это можно сделать с помощью сборки в DrawerLayout? Есть ли какая-то реализация для этого?


person Emil Adz    schedule 19.11.2013    source источник


Ответы (3)


Вы можете выполнить этот эффект с помощью ActionBarDrawerToggle в библиотеке поддержки v4.

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

Пример с кодом:

main_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<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">

    <FrameLayout android:id="@+id/content_frame"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>    

    <ListView android:id="@+id/left_drawer"
    android:layout_width="240dp"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:choiceMode="singleChoice"
    android:divider="@android:color/transparent"
    android:dividerHeight="0dp"/>

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

Теперь в вашей деятельности, которая содержит ящик:

public class ConfigurerActivity extends ActionBarActivity 
{
    private DrawerLayout mDrawerLayout;
    private ListView mDrawerList;
    private ActionBarDrawerToggle mDrawerToggle;
    private FrameLayout frame;
    private float lastScale = 1.0f;

    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_layout);

        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mDrawerList = (ListView) findViewById(R.id.left_drawer);
        frame = (FrameLayout) findViewById(R.id.content_frame);

        mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.drawable.ic_drawer, R.string.acc_drawer_open, R.string.acc_drawer_close) 
        {            
            @SuppressLint("NewApi")
            public void onDrawerSlide(View drawerView, float slideOffset)
            {
                float min = 0.9f;
                float max = 1.0f;
                float scaleFactor = (max - ((max - min) * slideOffset));

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) 
                {
                    frame.setScaleX(scaleFactor);
                    frame.setScaleY(scaleFactor);
                }
                else
                {               
                    ScaleAnimation anim = new ScaleAnimation(lastScale, scaleFactor, lastScale, scaleFactor, frame.getWidth()/2, frame.getHeight()/2);
                    anim.setDuration(0);
                    anim.setFillAfter(true);
                    frame.startAnimation(anim);

                    lastScale = scaleFactor;
                }
            }
        };

        mDrawerLayout.setDrawerListener(mDrawerToggle);

        // ... more of your code
    }
}

Обратите внимание, что я использую 2 разных метода для масштабирования, потому что setScaleX/Y недоступен в версиях PRE - Honeycomb для Android.

При этом вы можете установить свой собственный масштабный коэффициент (я думаю, что 0,9f достаточно мал) или, возможно, попробовать новые эффекты (изменить цвет) на основе процента открытия ящика.

Надеюсь, поможет.

person nsL    schedule 30.11.2013
comment
Большое спасибо, это похоже на правильный ответ, моя единственная проблема заключается в том, что в моем приложении действие NavDrawer в основном представляет собой действие-оболочку для всех других действий, которые у меня есть, поэтому макет, который я хочу изменить, не сидит прямо в та же активность, поэтому я понятия не имею, как получить ее экземпляр. Это экземпляр фрейма в вашем примере. Я посмотрю, что я могу сделать, и скоро приму ваш ответ. - person Emil Adz; 30.11.2013
comment
Ваше решение идеально, я протестировал его, внес необходимые изменения в свой код, и оно работает так, как ожидалось. Хорошее дополнение с методами анимации для разных версий SDK, хотя я уже знал об этом, но может быть полезен другим. Большое спасибо : ) - person Emil Adz; 30.11.2013
comment
я рад, что это помогло вам! - person nsL; 01.12.2013
comment
Идеальный. Большое спасибо - person Jiju Induchoodan; 07.05.2014
comment
Если ящик значков (ic_drawer) не движется или не переключается. Просто удалите слушателей onDrawerClose и onDrawerOpen и измените оператор if на slideOffset, на который ссылается здесь stackoverflow.com/a/23373562/1309629 - person Cjames; 03.06.2014
comment
Это полезно, но можем ли мы масштабировать, не сдвигая содержимое вправо? Когда я уменьшаю коэффициент min, кажется, что контент исчезает. - person Ralphilius; 06.11.2015
comment
@Ralphilius, содержимое не смещается, а просто уменьшается. Проверьте 2 последних параметра ScaleAnimation. Это опорные значения (X, Y), от которых происходит масштабирование. Прямо сейчас я использую центр представления, но вы можете поиграть с этими значениями и изменить масштаб (например, уменьшить, но один угол будет зафиксирован на своем месте). - person nsL; 06.11.2015
comment
@nsL да, я понимаю, что он уменьшается до центра, мне просто интересно, как заставить его оставаться слева. Я играл с минимальным/максимальным числом, но до сих пор не уверен, как эта штука работает.. - person Ralphilius; 07.11.2015

Эй, вы также можете дать лучший эффект для небольшой активности. Проверьте ResideMenu.

демо с библиотекой.

person Sachin    schedule 04.11.2014

если вы взглянете на стороннюю библиотеку SlidingMenu, в ней должно быть все, что вам нужно.

Бит, который вас интересует, это behindScrollScale, который говорит следующее:

backScrollScale — число с плавающей запятой, представляющее взаимосвязь между прокруткой вышеприведенного представления и прокруткой представления позади. Если установлено значение 0,5f, вид сзади будет прокручиваться на 1 пиксель на каждые 2 пикселя, на которые прокручивается вид сверху. Если установлено значение 1.0f, вид сзади будет прокручиваться на 1 пиксель на каждый 1 пиксель, на который прокручивается вид сверху. А если установлено значение 0.0f, вид сзади никогда не будет прокручиваться; это будет статично. С этим интересно поиграть. По умолчанию 0,25f.

person panini    schedule 19.11.2013
comment
Я думаю, вы можете быть правы, но правильно я использую сборку в DrawerLayout, и я не очень хочу менять эту реализацию, а добавлять к ней. Есть ли другой способ сделать это? - person Emil Adz; 21.11.2013
comment
не с родным DrawerLayout я не думаю. В рекомендациях Google по дизайну для DrawerLayout указано, что содержимое не должно перемещаться и Ящик должен отображаться поверх содержимого, поэтому я сомневаюсь, что они поддержат что-то, что нарушает это. - person panini; 22.11.2013