元のアドレス: http://www.codefrom.com/c/198
視差スクロールは一般的なアニメーション効果です。視差という用語は天文学に由来していますが、日常生活にも現れます。スピードを上げている電車の中で風景を見ると、近くにあるほど相対的な動きが速くなっているのに、遠くの山や川はゆっくりとしか動いていないことがわかります。これが最も一般的な視差効果です。視差アニメーションの独自のレイヤー化により、非常にリアルな視覚体験を実現できます。iOS、Android ランチャー、および Web サイト はすべて、ユーザーの視覚的な楽しみを向上させるための最良の選択として視差アニメーションを使用します。
クライアント アプリケーションを初めて開くときにブート ページが表示されるのは新しいことではなく、ViewPager とデザイナーが注意深く描いたいくつかの絵があれば、数分で完了できます。しかし、普通のものを特別なものにする人は常に存在します。たとえば、この記事の Zhihu クライアントや、Sina Weibo の新年バージョン、Baidu Tieba の特定のバージョンなど、視差アニメーションが多くのアプリケーションに登場しています。ユーザーの指の動き、スワイプ、フィードバックは、スマートで実際に近いビジュアルと操作体験であり、アプリケーションの第一印象はすぐに非常に高いレベルに引き上げられます。
私が最も印象に残ったのは、昨年の新浪微博の旧正月バージョンの紹介ページで、赤い切り絵の子供たちが描かれていました。インターフェースをスライドすると、これらの要素が感じられます。それは本当にスマートで、子供の頃の思い出を思い出させ、風味に満ちています。しかし、新年をどう過ごすかは新浪微博とは関係ありませんが、このスタートアップページは私にとって非常に人気があります。ただ、このバージョンの Weibo が見つからないのです。2 日前に Zhihu のスタートアップ ページが非常に優れているのを見つけたので、練習のために使用しました。
この記事では、Zhihu Android クライアントの起動ページを例として、視差スクロール効果を実現する方法を説明します。
Zhihu スタートアップ ページを慎重に操作してみると、視差アニメーションが主に背景レイヤーのグラデーションとコンテンツ レイヤー要素の差動スクロールに反映されていることを分析するのは難しくありません。アニメーションの内容は次のとおりです。
- コンテンツ: 要素の差分スクロール、視差効果を形成します ()
- 背景: インターフェイスがスライドすると、色が徐々に濃い青から水色に変わります ()
- テキスト: ページが変わると、下部のプロンプト コピーが切り替わります。シンプルなフェードインとフェードアウト効果付き
- インターフェイスアニメーション: インターフェイスの開始、要素の外観アニメーション (最初のページと最後のページ)
その他の項目は比較的単純なので、この記事では主に視差アニメーションと背景の実装について説明します他の項目については、以下のコードを参照してください。
ここでの視差スクロール効果は、主にコンテンツ要素のスクロール速度の違いに反映されます。たとえば、ViewPager が 1px スライドすると、A 要素は 2px 移動し、B 要素は 1.5px 移動します。この動きのギャップの比率を視差係数または視差率と呼びます。まさに同じインターフェースにあるものと同じであり、レベルが異なることで要素に異なる視差係数が与えられ、移動速度の違いが視差の錯覚を形成します。これが私たちが追求したい効果です。
ViewPager.OnPageChangeListenerを使うと動的計算が楽になります。いいえ、いいえ、後で背景のグラデーション効果を完成させるためにこれを計算する必要がありますが、ViewPager はすでに変換要素を準備していますtransformium: ViewPager.PageTransformer、これには抽象メソッドtransformPage(View page, floatposition)、私たちだけの完全オーダーメイド視差アニメーション。
ViewPager.PageTransformer
PageTransformer は、ViewPager がスライドするとトリガーされ、カスタム ページでのビュー変換の扉が開きます。
javapublic abstract void transformPage (View page, float position)
ViewPager のソース コードでは、その呼び出しプロセスを直感的に確認できます:
java// ViewPager#onPageScrolledif (mPageTransformer != null) { final int scrollX = getScrollX(); final int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { final View child = getChildAt(i); final LayoutParams lp = (LayoutParams) child.getLayoutParams(); if (lp.isDecor) continue; final float transformPos = (float) (child.getLeft() - scrollX) / getClientWidth(); mPageTransformer.transformPage(child, transformPos); }}
Param 1: View page
上記のコードから、そのページが現在スライドされているページであることを確認するのは難しくありません。デバッグの結果、各 子ビュー が NoSaveStateFrameLayout によってラップされていることがわかりました。これは、page.getChildAt(0) が各ページの実際の 子ビュー であることを意味します。
パラメータ 2: float 位置
position このパラメータは、コードやドキュメントを見ないと常によく知られている整数の位置と間違われますが、実際にはスライド ページの相対的な比率であり、本質的には 1 と同じです。 、 2 、 3 、 4 この位置は同じです。
たとえば、Zhihu スタートアップ ページには、A、B、C、D、E、Fの合計 6 ページがあります。初期状態は A です。ページが静的な場合、A ページの位置は正確に 0、B ページは 1 です。次に、ページをスライドします (B -> A)。このプロセスでは、A の位置は [-1, 0] の間にあり、B の位置は [0, 1] の間にあります。
ただし、このパラメータのドキュメントは単純であり、上記の例と比較すると十分に直感的ではありません。
Position of page relative to the current front-and-center position of the pager. 0 is front and center. 1 is one full page position to the right, and -1 is one page position to the left.
ParallaxTransformer
根据上面的分析,我们可以得出一个相对简单的自定义 transformer ,对 page view 进行遍历,递增或者递减其 parallaxCofficient ,以得到我们预期的效果,具体的系数设置请参考代码。
javaclass ParallaxTransformer implements ViewPager.PageTransformer { float parallaxCoefficient; float distanceCoefficient; public ParallaxTransformer(float parallaxCoefficient, float distanceCoefficient) { this.parallaxCoefficient = parallaxCoefficient; this.distanceCoefficient = distanceCoefficient; } @Override public void transformPage(View page, float position) { float scrollXOffset = page.getWidth() * parallaxCoefficient; // ... // layer is the id collection of views in this page for (int id : layer) { View view = page.findViewById(id); if (view != null) { view.setTranslationX(scrollXOffset * position); } scrollXOffset *= distanceCoefficient; } }}
留心才会发现,从第一页滑动到最后一页,背景色会平滑的从深蓝色过度到浅蓝色,这种效果又该怎么实现呢?
用过 Property Animation 的同学应该知道,以前的 Animation 只能用在 View 上,而 Property Animation 却可以用在任意类型属性值上,这归功于 TypeEvaluator 。
正好我们有 ArgbEvaluator ,它可以估算两个颜色值之间,任意部分的色值。因此,只需要指定起始色值以及最终的色值,传入滑动所对应的 fraction 即当前位置相对总距离的比例值,即可获得相应的色值。
javapublic class ArgbEvaluator implements TypeEvaluator { public Object evaluate(float fraction, Object startValue, Object endValue) { // ... }}
当然,前面说到需要使用 ViewPager.OnPageChangeListener 的:
javaclass GuidePageChangeListener implements ViewPager.OnPageChangeListener { ArgbEvaluator mColorEvaluator; int mPageWidth, mTotalScrollWidth; int mGuideStartBackgroundColor, mGuideEndBackgroundColor; public GuidePageChangeListener() { mColorEvaluator = new ArgbEvaluator(); mPageWidth = getWindowManager().getDefaultDisplay().getWidth(); mTotalScrollWidth = mPageWidth * mAdapter.getCount(); mGuideStartBackgroundColor = getResources().getColor(R.color.guide_start_background); mGuideEndBackgroundColor = getResources().getColor(R.color.guide_end_background); } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { float ratio = (mPageWidth * position + positionOffsetPixels) / (float) mTotalScrollWidth; Integer color = (Integer) mColorEvaluator.evaluate(ratio, mGuideStartBackgroundColor, mGuideEndBackgroundColor); mPager.setBackgroundColor(color); } @Override public void onPageSelected(int position) {} @Override public void onPageScrollStateChanged(int state) {}}
代码已经 push 到 Github 了,诸位自取。不过请注意,其素材均取自于知乎 Android 客户端(你懂的),学习交流即可,请勿用作商业用途。
还求更优雅的实现方式,欢迎发起 pull request 。
Github : Zhihu-Parallax-Animation
原文地址:http://www.codefrom.com/c/198
更多技术文章请访问:码源|专注开源技术分享