parallax(視差)の効果のソースコード分析
16689 ワード
転載は出所を明記してください.
http://blog.csdn.net/coder_nice/articale/detail/45311715
視差概念
多分多くの人はparallaxの概念を知らないかもしれません.まず動画を見に来てください.
この図があるならば、パララックスの視差の概念が分かります.google palyはこの効果があります.多くの人が効果図を見たら、すぐにリンクを得て、いい人が最後までやりたいと思います.githubアドレス
最初の考え
最初にデザイナーからこの効果を要求された時、自分でよく考えました.一つのFraam Layoutの中に二層のviewが含まれています.下の階はスライドに従って視差の効果が現れるparallax viewです.上の階は普通のviewで、ジェスチャーのスライドに従ってスライドします.上の方のスライド速度を下の方のパラレークスビューに伝えて、速度値を小さくしてください.これも多くの人の考えかもしれません.githubに接触したこのオープンソースプロジェクトの後、コードを見てみましたが、これよりはるかに簡単です.
ソース分析
ここでは最もよく使われているParalaxScrrollViewの視差効果のあるScrrollViewの解析だけをして、まずコードを見ます.ParalaxScrrollViewソース
ParaxScrrollViewのソースコードはまだ簡単です.ほとんどのコードは説明せずにわかると思います.大体の流れはParalaxScrrollViewを作成した後、TypedArayのいくつかのパラメータ(最初の速度減衰率、色グラデーション率、視差の速度減衰率、視差効果view個数)をロードして、視差効果のあるviewを必要とします.(numOfParallaxViewパラメータを用いてget ChildAt法により取得した)パラメータとしてScrrollView ParalexedItemを作成し(視差効果のある方法のviewは、単にカプセル化されているだけ)、その後はparallaxedviewsリストに追加して、オンScrrollChend()方法の中で循環するparallaxedviewsリストは、各視差が必要なviewをこのジェスチャーでスライドする視差効果を設定してOKです.
重点的にonScrrollChangedの方法を話します.
APIの説明を見てください
APIを見て、viewのこの方法をどう説明しますか?
作者(コードの持ち主)の考えを理解してください.
著者は、ユーザがスクリーンをスライドさせるたびに、ScrelViewのオンスクリーン()に視差view距離の上部の位置を設定したいです.このように視差viewの滑り速度が遅く、通常のviewの滑りが速い効果が現れました.伝達速度のような数値は全く必要ないです.ただ簡単に頂上までの位置を設定して、問題を簡略化しました.
締め括りをつける
私は比較的簡単なParalaxScrrollViewのソースコードだけを話しましたが、他のいくつかのやや複雑な視差ViewのParalaxListView、ParaxExpandable ListViewも大同小異です.問題を理解するのはもちろん簡単に始めるべきです.
http://blog.csdn.net/coder_nice/articale/detail/45311715
視差概念
多分多くの人はparallaxの概念を知らないかもしれません.まず動画を見に来てください.
この図があるならば、パララックスの視差の概念が分かります.google palyはこの効果があります.多くの人が効果図を見たら、すぐにリンクを得て、いい人が最後までやりたいと思います.githubアドレス
最初の考え
最初にデザイナーからこの効果を要求された時、自分でよく考えました.一つのFraam Layoutの中に二層のviewが含まれています.下の階はスライドに従って視差の効果が現れるparallax viewです.上の階は普通のviewで、ジェスチャーのスライドに従ってスライドします.上の方のスライド速度を下の方のパラレークスビューに伝えて、速度値を小さくしてください.これも多くの人の考えかもしれません.githubに接触したこのオープンソースプロジェクトの後、コードを見てみましたが、これよりはるかに簡単です.
ソース分析
ここでは最もよく使われているParalaxScrrollViewの視差効果のあるScrrollViewの解析だけをして、まずコードを見ます.ParalaxScrrollViewソース
public class ParallaxScrollView extends ScrollView {
private static final int DEFAULT_PARALLAX_VIEWS = 1;
private static final float DEFAULT_INNER_PARALLAX_FACTOR = 1.9F;
private static final float DEFAULT_PARALLAX_FACTOR = 1.9F;
private static final float DEFAULT_ALPHA_FACTOR = -1F;
private int numOfParallaxViews = DEFAULT_PARALLAX_VIEWS;
private float innerParallaxFactor = DEFAULT_PARALLAX_FACTOR;
private float parallaxFactor = DEFAULT_PARALLAX_FACTOR;
private float alphaFactor = DEFAULT_ALPHA_FACTOR;
private ArrayList<ParallaxedView> parallaxedViews = new ArrayList<ParallaxedView>();
public ParallaxScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs);
}
public ParallaxScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public ParallaxScrollView(Context context) {
super(context);
}
protected void init(Context context, AttributeSet attrs) {
TypedArray typeArray = context.obtainStyledAttributes(attrs, R.styleable.ParallaxScroll);
this.parallaxFactor = typeArray.getFloat(R.styleable.ParallaxScroll_parallax_factor, DEFAULT_PARALLAX_FACTOR);
this.alphaFactor = typeArray.getFloat(R.styleable.ParallaxScroll_alpha_factor, DEFAULT_ALPHA_FACTOR);
this.innerParallaxFactor = typeArray.getFloat(R.styleable.ParallaxScroll_inner_parallax_factor, DEFAULT_INNER_PARALLAX_FACTOR);
this.numOfParallaxViews = typeArray.getInt(R.styleable.ParallaxScroll_parallax_views_num, DEFAULT_PARALLAX_VIEWS);
typeArray.recycle();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
makeViewsParallax();
}
private void makeViewsParallax() {
if (getChildCount() > 0 && getChildAt(0) instanceof ViewGroup) {
ViewGroup viewsHolder = (ViewGroup) getChildAt(0);
int numOfParallaxViews = Math.min(this.numOfParallaxViews, viewsHolder.getChildCount());
for (int i = 0; i < numOfParallaxViews; i++) {
ParallaxedView parallaxedView = new ScrollViewParallaxedItem(viewsHolder.getChildAt(i));
parallaxedViews.add(parallaxedView);
}
}
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
float parallax = parallaxFactor;
float alpha = alphaFactor;
for (ParallaxedView parallaxedView : parallaxedViews) {
parallaxedView.setOffset((float)t / parallax);
parallax *= innerParallaxFactor;
if (alpha != DEFAULT_ALPHA_FACTOR) {
float fixedAlpha = (t <= 0) ? 1 : (100 / ((float)t * alpha));
parallaxedView.setAlpha(fixedAlpha);
alpha /= alphaFactor;
}
parallaxedView.animateNow();
}
}
protected class ScrollViewParallaxedItem extends ParallaxedView {
public ScrollViewParallaxedItem(View view) {
super(view);
}
@Override
protected void translatePreICS(View view, float offset) {
view.offsetTopAndBottom((int)offset - lastOffset);
lastOffset = (int)offset;
}
}
}
ParalaxedViewソースpublic abstract class ParallaxedView {
static public boolean isAPI11 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
protected WeakReference<View> view;
protected int lastOffset;
protected List<Animation> animations;
abstract protected void translatePreICS(View view, float offset);
public ParallaxedView(View view) {
this.lastOffset = 0;
this.animations = new ArrayList<Animation>();
this.view = new WeakReference<View>(view);
}
public boolean is(View v) {
return (v != null && view != null && view.get() != null && view.get().equals(v));
}
@SuppressLint("NewApi")
public void setOffset(float offset) {
View view = this.view.get();
if (view != null)
if (isAPI11) {
view.setTranslationY(offset);
} else {
translatePreICS(view, offset);
}
}
public void setAlpha(float alpha) {
View view = this.view.get();
if (view != null)
if (isAPI11) {
view.setAlpha(alpha);
} else {
alphaPreICS(view, alpha);
}
}
protected synchronized void addAnimation(Animation animation) {
animations.add(animation);
}
protected void alphaPreICS(View view, float alpha) {
addAnimation(new AlphaAnimation(alpha, alpha));
}
protected synchronized void animateNow() {
View view = this.view.get();
if (view != null) {
AnimationSet set = new AnimationSet(true);
for (Animation animation : animations)
if (animation != null)
set.addAnimation(animation);
set.setDuration(0);
set.setFillAfter(true);
view.setAnimation(set);
set.start();
animations.clear();
}
}
public void setView(View view) {
this.view = new WeakReference<View>(view);
}
大体の流れParaxScrrollViewのソースコードはまだ簡単です.ほとんどのコードは説明せずにわかると思います.大体の流れはParalaxScrrollViewを作成した後、TypedArayのいくつかのパラメータ(最初の速度減衰率、色グラデーション率、視差の速度減衰率、視差効果view個数)をロードして、視差効果のあるviewを必要とします.(numOfParallaxViewパラメータを用いてget ChildAt法により取得した)パラメータとしてScrrollView ParalexedItemを作成し(視差効果のある方法のviewは、単にカプセル化されているだけ)、その後はparallaxedviewsリストに追加して、オンScrrollChend()方法の中で循環するparallaxedviewsリストは、各視差が必要なviewをこのジェスチャーでスライドする視差効果を設定してOKです.
重点的にonScrrollChangedの方法を話します.
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
float parallax = parallaxFactor;
float alpha = alphaFactor;
for (ParallaxedView parallaxedView : parallaxedViews) {
parallaxedView.setOffset((float)t / parallax);
parallax *= innerParallaxFactor;
if (alpha != DEFAULT_ALPHA_FACTOR) {
float fixedAlpha = (t <= 0) ? 1 : (100 / ((float)t * alpha));
parallaxedView.setAlpha(fixedAlpha);
alpha /= alphaFactor;
}
parallaxedView.animateNow();
}
}
forループは、複数の視差viewがあるときに使用されます.alphaはグラデーションで使用され、視差の役割を果たすのはこの言葉です.parallaxedView.setOffset((float)t / parallax);
この言葉の方法体の中で何をしていますか? @SuppressLint("NewApi")
public void setOffset(float offset) {
View view = this.view.get();
if (view != null)
if (isAPI11) {
view.setTranslationY(offset);
} else {
translatePreICS(view, offset);
}
}
APIが11より大きい時に使うのはこの方法view.set Translation Yで、11より小さい時に使うview.offset TopAndBottom(int)offset-lastOffsetです.この方法は高いバージョンのview.set Translation(offset)方法だけを見ます.APIの説明を見てください
APIを見て、viewのこの方法をどう説明しますか?
Sets the vertical location of this view relative to its top position. This effectively positions the object post-layout, in addition to wherever the object's layout placed it.
Related XML Attributes
android:translationY
Parameters
translationY The vertical position of this view relative to its top position, in pixels.
縦方向のview上部に対する位置を設定します.この位置はオブジェクトがlayout()メソッドを呼び出した後に有効になります.このオブジェクトのlayout()メソッドの中にそれを再配置した場合だけ有効になりません.作者(コードの持ち主)の考えを理解してください.
著者は、ユーザがスクリーンをスライドさせるたびに、ScrelViewのオンスクリーン()に視差view距離の上部の位置を設定したいです.このように視差viewの滑り速度が遅く、通常のviewの滑りが速い効果が現れました.伝達速度のような数値は全く必要ないです.ただ簡単に頂上までの位置を設定して、問題を簡略化しました.
締め括りをつける
私は比較的簡単なParalaxScrrollViewのソースコードだけを話しましたが、他のいくつかのやや複雑な視差ViewのParalaxListView、ParaxExpandable ListViewも大同小異です.問題を理解するのはもちろん簡単に始めるべきです.