1. ホーム
  2. android

Lollipopツールバーのアニメーション(Telegramアプリ)の展開・折りたたみについて

2023-08-18 02:55:57

質問

ツールバーの展開・折りたたみのアニメーションがどのように行われているのか、知りたいです。Telegram アプリの設定を見てもらうと、リストビューとツールバーがあることがわかると思います。下にスクロールするとツールバーが折りたたまれ、上にスクロールするとツールバーが展開されます。また、プロフィール写真とFABのアニメーションがあります。どなたか手がかりをお持ちの方はいらっしゃいますか?その上にすべてのアニメーションを構築しているのでしょうか?もしかしたら、私は新しいAPIやサポートライブラリから何かを見逃しているかもしれません。

Google カレンダー アプリで、スピナー (スピナーではないと思いますが、そのように見えます) を開くと、同じ動作に気づきました。ツール バーが展開され、上にスクロールすると、ツール バーが折りたたまれます。

はっきり言いますが、QuickReturnメソッドは必要ありません。おそらく Telegram アプリが似たようなものを使用していることは知っています。私が必要とする正確なメソッドは、Google カレンダー アプリの効果です。私は、以下の方法で試してみました。

android:animateLayoutChanges="true"

で、expandメソッドはかなりうまく動作します。しかし、明らかに、私がListViewを上にスクロールした場合、ツールバーは折りたたまれません。

を追加することも考えました。 GestureListener を追加することも考えましたが、これを実現するAPIやより簡単な方法があれば知りたいのです。

ないのであれば、やはり GestureListener . うまくいけば、アニメーションの効果がスムーズに出るかもしれません。

ありがとうございます。

どのように解決するのですか?

編集する。

Android Designサポートライブラリがリリースされたので、より簡単に解決できるようになりました。確認 joaquin さんの回答

--

おそらく他にも多くの解決策があると思いますが、私の場合はこれでうまくいきました。

  1. まず最初に Toolbar を透明な背景で表示します。展開する & 折り畳む Toolbar は実際には の偽物です。 の下にあるもので、透明な Toolbar . (下の最初のスクリーンショット - 余白のあるもの - を見れば、これがTelegramでのやり方でもあることがわかります)。

    私たちが保持するのは、実際の Toolbar に対して NavigationIcon で、オーバーフローの MenuItem .

    <イグ

  2. 2 番目のスクリーンショットの赤い四角の中にあるものすべて (つまり、偽の ToolbarFloatingActionButton ) は実際には ヘッダ に追加するもので、設定に 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 の拡張をアニメーション化するために、私たちは ListView onScrollListener .

    // 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. minHeaderHeight を置き換えて、minHeaderTranslation という別の変数を導入しました。
  2. ヘッダーViewに適用されるY変換の値を、:

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

    になります。

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

    前の表現が全く機能していませんでした、申し訳ありません...。

  3. 比率の計算も変更され、ツールバーの下部 (画面の上部ではなく) から完全に展開されたヘッダーに展開されるようになりました。