Развернуть / свернуть анимацию панели инструментов Lollipop (приложение Telegram)
Я пытаюсь выяснить, как развернуть/свернуть анимации, панели инструментов сделано. Если вы посмотрите на Настройки приложения Telegram, вы увидите, что есть listview и панель инструментов. При прокрутке вниз панель инструментов сворачивается, а при прокрутке вверх она расширяется. Существует также анимация профиля pic и FAB. У кого-нибудь есть какие-нибудь идеи на этот счет? Вы думаете, они построили все анимации на нем? Может быть, мне чего-то не хватает в новых API или поддержке библиотека.
Я заметил такое же поведение в приложении Google calendar, когда вы открываете Spinner (я не думаю, что это spinner, но похоже): панель инструментов расширяется, и когда вы прокручиваете вверх, она сворачивается.
просто чтобы прояснить: мне не нужен метод QuickReturn. Я знаю, что, вероятно, приложение Telegram использует что-то подобное. Точный метод, который мне нужен, - это эффект приложения Google Calendar. Я пробовал с
android:animateLayoutChanges="true"
и метод expand работает довольно что ж. Но очевидно, что если я прокручиваю ListView, панель инструментов не сворачивается.
Я также думал о добавлении GestureListener но я хочу знать, есть ли какие-либо API или более простые методы достижения этого.
если их нет, я думаю, что пойду с GestureListener. Надеюсь, чтобы иметь плавный эффект анимации.
спасибо!
4 ответов:
Edit:
С момента выпуска библиотеки поддержки дизайна Android, есть более простое решение. Проверьте Хоакина ответ
--
вот как я это сделал, вероятно, есть много других решений, но этот работал для меня.
прежде всего, вы должны использовать
ToolbarС прозрачным фоном. Расширение и сворачиваниеToolbarна самом деле подделка один это под прозрачнымToolbar. (вы можете видеть на первом скриншоте ниже-тот, с полями-что это также, как они сделали это в Telegram).мы только сохраняем фактическое
ToolbarнаNavigationIconи переливнойMenuItem.
все, что в красном прямоугольнике на втором скриншоте (т. е. фейк
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)теперь начинается самое интересное. Для того, чтобы оживить расширение поддельные
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:
были некоторые ошибки в коде выше (что я не тестировал до сегодняшнего дня...), поэтому я изменил несколько строк, чтобы заставить его работать:
- я ввел другую переменную, minHeaderTranslation, которая заменила minHeaderHeight;
я изменил значение перевода в случае просмотра заголовков от :
headerView.setTranslationY(Math.max(-scrollY, minHeaderTranslation));to:
headerView.setTranslationY(Math.max(0, scrollY + minHeaderTranslation));Предыдущее выражение не работало вообще, я сожалею об этом...
расчет отношения также изменился, так что теперь он развивается от нижней панели инструментов (вместо верхней части экрана) до полного развернутого заголовка.
также проверить
CollapsingTitleLayoutнаписано Крисом Бэйнсом в команде Android: https://plus.google.com/+ChrisBanes/posts/J9Fwbc15BHN
использовать библиотеку поддержки проектирования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