69

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

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

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

android:animateLayoutChanges="true" 

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

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

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

Спасибо!

ответ

104

Edit:

С момента выхода библиотеки поддержки Android Design, есть простое решение. Проверить joaquin's answer

-

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

  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> 
    

    (Обратите внимание, что вы можете использовать отрицательные поля/отступы для ФАБ быть трансзональных на 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. Я изменил значение перевода Y применяется к заголовку Вид с:

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

    к:

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

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

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

+5

Не заголовок исчезнет, ​​как только вы перечисляете слишком далеко? Заголовки Afaik также перерабатываются, поэтому, даже если вы переводите свой заголовок, чтобы он выглядел так, будто он закреплен на вершине, я думаю, что он просто исчезнет, ​​как только фактическое положение исчезнет из поля зрения. – Kuno

+0

Ты прав Куно. Я не пытался, но это ожидаемое поведение. Вот почему я использовал панель инструментов внутри FrameLayout. Основное содержимое находится над панелью инструментов с помощью marginTop x. Чтобы воспроизвести анимацию, я просто переводил основное содержимое между осью Y – edoardotognoni

+0

@FedeAmura Sweet, но я думаю, что FAB слишком низок, когда он находится внизу экрана :) – MathieuMaree

1

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

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 
     } 

    } 
8

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

включить это в строй ,Gradle

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

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

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> 
+0

Очень приятно, любя эту поддержку дизайна lib – Luke

+0

И я ненавижу это, меняет все время. К сожалению, мне придется следовать за ним. – Yar

 Смежные вопросы

  • Нет связанных вопросов^_^