Развернуть / свернуть анимацию панели инструментов Lollipop (приложение Telegram)



Я пытаюсь выяснить, как развернуть/свернуть анимации, панели инструментов сделано. Если вы посмотрите на Настройки приложения Telegram, вы увидите, что есть listview и панель инструментов. При прокрутке вниз панель инструментов сворачивается, а при прокрутке вверх она расширяется. Существует также анимация профиля pic и FAB. У кого-нибудь есть какие-нибудь идеи на этот счет? Вы думаете, они построили все анимации на нем? Может быть, мне чего-то не хватает в новых API или поддержке библиотека.



Я заметил такое же поведение в приложении Google calendar, когда вы открываете Spinner (я не думаю, что это spinner, но похоже): панель инструментов расширяется, и когда вы прокручиваете вверх, она сворачивается.



просто чтобы прояснить: мне не нужен метод QuickReturn. Я знаю, что, вероятно, приложение Telegram использует что-то подобное. Точный метод, который мне нужен, - это эффект приложения Google Calendar. Я пробовал с



android:animateLayoutChanges="true"


и метод expand работает довольно что ж. Но очевидно, что если я прокручиваю ListView, панель инструментов не сворачивается.



Я также думал о добавлении GestureListener но я хочу знать, есть ли какие-либо API или более простые методы достижения этого.



если их нет, я думаю, что пойду с GestureListener. Надеюсь, чтобы иметь плавный эффект анимации.



спасибо!

641   4  

4 ответов:

Edit:

С момента выпуска библиотеки поддержки дизайна Android, есть более простое решение. Проверьте Хоакина ответ

--

вот как я это сделал, вероятно, есть много других решений, но этот работал для меня.

  1. прежде всего, вы должны использовать Toolbar С прозрачным фоном. Расширение и сворачивание Toolbar на самом деле подделка один это под прозрачным Toolbar. (вы можете видеть на первом скриншоте ниже-тот, с полями-что это также, как они сделали это в Telegram).

    мы только сохраняем фактическое Toolbar на NavigationIcon и переливной MenuItem.

    1. Transparent Toolbar - 2. Expanded header - 3. Collapsed header

  2. все, что в красном прямоугольнике на втором скриншоте (т. е. фейк Toolbar и FloatingActionButton) на самом деле заголовок что вы добавляете в настройки ListView (или ScrollView).

    таким образом, вы должны создать макет для этого заголовка в отдельном файле, который может выглядеть следующим образом :

     <!-- The headerView layout. Includes the fake Toolbar & the FloatingActionButton -->
    
     <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    
        <RelativeLayout
            android:id="@+id/header_container"
            android:layout_width="match_parent"
            android:layout_height="@dimen/header_height"
            android:layout_marginBottom="3dp"
            android:background="@android:color/holo_blue_dark">
    
            <RelativeLayout
                android:id="@+id/header_infos_container"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_alignParentBottom="true"
                android:padding="16dp">
    
                <ImageView
                    android:id="@+id/header_picture"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerVertical="true"
                    android:layout_marginRight="8dp"
                    android:src="@android:drawable/ic_dialog_info" />
    
                <TextView
                    android:id="@+id/header_title"
                    style="@style/TextAppearance.AppCompat.Title"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_toRightOf="@+id/header_picture"
                    android:text="Toolbar Title"
                    android:textColor="@android:color/white" />
    
                <TextView
                    android:id="@+id/header_subtitle"
                    style="@style/TextAppearance.AppCompat.Subhead"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_below="@+id/header_title"
                    android:layout_toRightOf="@+id/header_picture"
                    android:text="Toolbar Subtitle"
                    android:textColor="@android:color/white" />
    
            </RelativeLayout>
        </RelativeLayout>
    
        <FloatingActionButton
            android:id="@+id/header_fab"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom|right"
            android:layout_margin="10dp"
            android:src="@drawable/ic_open_in_browser"/>
    
    </FrameLayout>
    

    (обратите внимание, что вы можете использовать отрицательные поля/заполнение для fab, чтобы оседлать на 2 Views)

  3. теперь начинается самое интересное. Для того, чтобы оживить расширение поддельные Toolbar мы реализуем ListViewonScrollListener.

    // The height of your fully expanded header view (same than in the xml layout)
    int headerHeight = getResources().getDimensionPixelSize(R.dimen.header_height);
    // The height of your fully collapsed header view. Actually the Toolbar height (56dp)
    int minHeaderHeight = getResources().getDimensionPixelSize(R.dimen.action_bar_height);
    // The left margin of the Toolbar title (according to specs, 72dp)
    int toolbarTitleLeftMargin = getResources().getDimensionPixelSize(R.dimen.toolbar_left_margin);
    // Added after edit
    int minHeaderTranslation;
    
    private ListView listView;
    
    // Header views
    private View headerView;
    private RelativeLayout headerContainer;
    private TextView headerTitle;
    private TextView headerSubtitle;
    private FloatingActionButton headerFab;
    
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        View rootView = inflater.inflate(R.layout.listview_fragment, container, false);
        listView = rootView.findViewById(R.id.listview);
    
        // Init the headerHeight and minHeaderTranslation values
    
        headerHeight = getResources().getDimensionPixelSize(R.dimen.header_height);
        minHeaderTranslation = -headerHeight + 
            getResources().getDimensionPixelOffset(R.dimen.action_bar_height);
    
        // Inflate your header view
        headerView = inflater.inflate(R.layout.header_view, listview, false);
    
        // Retrieve the header views
        headerContainer = (RelativeLayout) headerView.findViewById(R.id.header_container);
        headerTitle = (TextView) headerView.findViewById(R.id.header_title);
        headerSubtitle = (TextView) headerView.findViewById(R.id.header_subtitle);
        headerFab = (TextView) headerView.findViewById(R.id.header_fab);;
    
        // Add the headerView to your listView
        listView.addHeaderView(headerView, null, false);
    
        // Set the onScrollListener
        listView.setOnScrollListener(this);        
    
        // ...
    
        return rootView;
    }
    
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState)
    {
        // Do nothing
    }
    
    
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)
    {
        Integer scrollY = getScrollY(view);
    
        // This will collapse the header when scrolling, until its height reaches
        // the toolbar height
        headerView.setTranslationY(Math.max(0, scrollY + minHeaderTranslation));
    
        // Scroll ratio (0 <= ratio <= 1). 
        // The ratio value is 0 when the header is completely expanded, 
        // 1 when it is completely collapsed
        float offset = 1 - Math.max(
            (float) (-minHeaderTranslation - scrollY) / -minHeaderTranslation, 0f);
    
    
        // Now that we have this ratio, we only have to apply translations, scales,
        // alpha, etc. to the header views
    
        // For instance, this will move the toolbar title & subtitle on the X axis 
        // from its original position when the ListView will be completely scrolled
        // down, to the Toolbar title position when it will be scrolled up.
        headerTitle.setTranslationX(toolbarTitleLeftMargin * offset);
        headerSubtitle.setTranslationX(toolbarTitleLeftMargin * offset);
    
        // Or we can make the FAB disappear when the ListView is scrolled 
        headerFab.setAlpha(1 - offset);
    }
    
    
    // Method that allows us to get the scroll Y position of the ListView
    public int getScrollY(AbsListView view)
    {
        View c = view.getChildAt(0);
    
        if (c == null)
            return 0;
    
        int firstVisiblePosition = view.getFirstVisiblePosition();
        int top = c.getTop();
    
        int headerHeight = 0;
        if (firstVisiblePosition >= 1)
            headerHeight = this.headerHeight;
    
        return -top + firstVisiblePosition * c.getHeight() + headerHeight;
    }
    

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

EDIT 2:

были некоторые ошибки в коде выше (что я не тестировал до сегодняшнего дня...), поэтому я изменил несколько строк, чтобы заставить его работать:

  1. я ввел другую переменную, minHeaderTranslation, которая заменила minHeaderHeight;
  2. я изменил значение перевода в случае просмотра заголовков от :

        headerView.setTranslationY(Math.max(-scrollY, minHeaderTranslation));
    

    to:

        headerView.setTranslationY(Math.max(0, scrollY + minHeaderTranslation));
    

    Предыдущее выражение не работало вообще, я сожалею об этом...

  3. расчет отношения также изменился, так что теперь он развивается от нижней панели инструментов (вместо верхней части экрана) до полного развернутого заголовка.

также проверить CollapsingTitleLayout написано Крисом Бэйнсом в команде Android: https://plus.google.com/+ChrisBanes/posts/J9Fwbc15BHN

enter image description here

код:https://gist.github.com/chrisbanes/91ac8a20acfbdc410a68

использовать библиотеку поддержки проектированияhttp://android-developers.blogspot.in/2015/05/android-design-support-library.html

включить это в build.gradle

compile 'com.android.support:design:22.2.0'    
compile 'com.android.support:appcompat-v7:22.2.+'

для просмотра recycler включите это также

compile 'com.android.support:recyclerview-v7:22.2.0' 

    <!-- AppBarLayout allows your Toolbar and other views (such as tabs provided by TabLayout) 
    to react to scroll events in a sibling view marked with a ScrollingViewBehavior.-->
    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fitsSystemWindows="true">

        <!-- specify tag app:layout_scrollFlags -->
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|enterAlways"/>

        <!-- specify tag app:layout_scrollFlags -->
        <android.support.design.widget.TabLayout
            android:id="@+id/tabLayout"
            android:scrollbars="horizontal"
            android:layout_below="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|enterAlways"/>

        <!--  app:layout_collapseMode="pin" will help to pin this view at top when scroll -->
        <TextView
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:text="Title"
            android:gravity="center"
            app:layout_collapseMode="pin" />

    </android.support.design.widget.AppBarLayout>

    <!-- This will be your scrolling view. 
    app:layout_behavior="@string/appbar_scrolling_view_behavior" tag connects this features -->
    <android.support.v7.widget.RecyclerView
        android:id="@+id/list"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </android.support.v7.widget.RecyclerView>

</android.support.design.widget.CoordinatorLayout>

ваша деятельность должна распространяться AppCompatActivity

public class YourActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.your_layout);

        //set toolbar
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
    }

}

ваша тема приложения должна быть такой

    <resources>
            <!-- Base application theme. -->   
            <style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
            </style>
    </resources>

Это моя реализация:

collapsedHeaderHeight и expandedHeaderHeight определены где-то еще, с функцией getAnimationProgress Я могу получить прогресс расширения/свертывания, основываясь на этом значении, я делаю свою анимацию и показываю/скрываю реальный заголовок.

  listForumPosts.setOnScrollListener(new AbsListView.OnScrollListener() {

        /**
         * @return [0,1], 0 means header expanded, 1 means header collapsed
         */
        private float getAnimationProgress(AbsListView view, int firstVisibleItem) {
            if (firstVisibleItem > 0)
                return 1;

            // should not exceed 1
            return Math.min(
                    -view.getChildAt(0).getTop() / (float) (expandedHeaderHeight - collapsedHeaderHeight), 1);
        }

        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
            // at render beginning, the view could be empty!
            if (view.getChildCount() > 0) {
                float animationProgress = getAnimationProgress(view, firstVisibleItem);
                imgForumHeaderAvatar.setAlpha(1-animationProgress);
                if (animationProgress == 1) {
                    layoutForumHeader.setVisibility(View.VISIBLE);
                } else {
                    layoutForumHeader.setVisibility(View.GONE);
                }
            }
        }

        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            // do nothing
        }

    }

Comments

    Ничего не найдено.