├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml └── vcs.xml ├── ParallaxEffectDemo.iml ├── README.md ├── app ├── .gitignore ├── app.iml ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── lvable │ │ └── parallaxeffectdemo │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── lvable │ │ └── parallaxeffectdemo │ │ ├── BundleKey.java │ │ ├── MainActivity.java │ │ ├── NormalParallaxActivity.java │ │ ├── NormalSlidePageFragment.java │ │ ├── ParallaxTransformer.java │ │ ├── SlidePagerAdapter.java │ │ ├── YahooParallaxActivity.java │ │ ├── YahooSlidePageFragment.java │ │ └── view │ │ ├── NotifyingScrollView.java │ │ └── SharpRectView.java │ └── res │ ├── drawable │ ├── ic_share_variant.png │ ├── icon1.png │ ├── icon2.png │ ├── icon3.png │ ├── p1.jpg │ ├── p2.jpg │ └── p3.jpg │ ├── layout │ ├── activity_main.xml │ ├── activity_normal_parallax.xml │ ├── activity_yahoo_parallax.xml │ ├── normal_slide_page.xml │ └── yahoo_page.xml │ ├── menu │ ├── menu_main.xml │ ├── menu_normal_parallax.xml │ └── menu_yahoo_parallax.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── demo1.gif ├── demo2.gif ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | /.idea/libraries 5 | .DS_Store 6 | /build 7 | /captures 8 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | ParallaxEffectDemo -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | Android Lint 15 | 16 | 17 | Class structure 18 | 19 | 20 | Compiler issues 21 | 22 | 23 | Control flow issues 24 | 25 | 26 | Error handling 27 | 28 | 29 | Error handlingGroovy 30 | 31 | 32 | Finalization issues 33 | 34 | 35 | General 36 | 37 | 38 | Groovy 39 | 40 | 41 | Inheritance issues 42 | 43 | 44 | Internationalization issues 45 | 46 | 47 | J2ME issues 48 | 49 | 50 | Java language level migration aids 51 | 52 | 53 | JavaBeans issues 54 | 55 | 56 | Numeric issues 57 | 58 | 59 | OtherGroovy 60 | 61 | 62 | Performance issues 63 | 64 | 65 | Potentially confusing code constructsGroovy 66 | 67 | 68 | Probable bugs 69 | 70 | 71 | Security issues 72 | 73 | 74 | Serialization issues 75 | 76 | 77 | Verbose or redundant code constructs 78 | 79 | 80 | XML 81 | 82 | 83 | 84 | 85 | Abstraction issues 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 107 | 108 | 109 | 110 | 111 | 112 | 117 | 118 | 119 | 120 | 121 | 122 | Android API 19 Platform 123 | 124 | 129 | 130 | 131 | 132 | 133 | 134 | 1.7 135 | 136 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 163 | 164 | 165 | 166 | 167 | 168 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /ParallaxEffectDemo.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ParallaxEffectDemo 2 | A simple parallax effect imitates the Yahoo Digest effect. 3 | ####Vertical & horizontal parallax effect 4 | ![image](https://github.com/qianlvable/ParallaxEffectDemo/blob/master/demo1.gif) 5 | 6 | ![image](https://github.com/qianlvable/ParallaxEffectDemo/blob/master/demo2.gif) 7 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/app.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 22 5 | buildToolsVersion "23.0.2" 6 | 7 | defaultConfig { 8 | applicationId "com.lvable.parallaxeffectdemo" 9 | minSdkVersion 14 10 | targetSdkVersion 21 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | compile 'com.android.support:appcompat-v7:22.1.1' 25 | } 26 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in G:\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/lvable/parallaxeffectdemo/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.lvable.parallaxeffectdemo; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 22 | 23 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/lvable/parallaxeffectdemo/BundleKey.java: -------------------------------------------------------------------------------- 1 | package com.lvable.parallaxeffectdemo; 2 | 3 | /** 4 | * Created by ningjiaqi on 16/3/11. 5 | */ 6 | public class BundleKey { 7 | public static final String PARALLAX_SPEED = "parallax_speed"; 8 | public static final String PARALLAX_DISTANCE = "parallax_distance"; 9 | public static final String TYPE_YAHOO = "type_yahoo"; 10 | public static final String TYPE_NORMAL = "type_normal"; 11 | public static final String PAGE_INDEX = "page_index"; 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/lvable/parallaxeffectdemo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.lvable.parallaxeffectdemo; 2 | 3 | import android.content.Intent; 4 | import android.support.v7.app.ActionBarActivity; 5 | import android.os.Bundle; 6 | import android.util.Log; 7 | import android.view.View; 8 | import android.widget.Button; 9 | import android.widget.SeekBar; 10 | 11 | 12 | public class MainActivity extends ActionBarActivity implements View.OnClickListener, 13 | SeekBar.OnSeekBarChangeListener{ 14 | 15 | public enum TYPE {YAHOO_TYPE,NORMAL_TYPE}; 16 | private float mDistanceVal = 0.6f; 17 | private float mSpeedVal = 0.6f; 18 | private static final String TAG = "MainActivity"; 19 | @Override 20 | protected void onCreate(Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | setContentView(R.layout.activity_main); 23 | 24 | Button btnYahoo = (Button)findViewById(R.id.btn_yahoo_effect); 25 | Button btnNormal = (Button)findViewById(R.id.btn_normal_effect); 26 | SeekBar speedSeekBar = (SeekBar)findViewById(R.id.speed_seekbar); 27 | SeekBar distanceSeekBar = (SeekBar)findViewById(R.id.distance_seekbar); 28 | 29 | btnYahoo.setOnClickListener(this); 30 | btnNormal.setOnClickListener(this); 31 | 32 | speedSeekBar.setOnSeekBarChangeListener(this); 33 | distanceSeekBar.setOnSeekBarChangeListener(this); 34 | } 35 | 36 | @Override 37 | public void onClick(View view) { 38 | Bundle bundle = new Bundle(); 39 | bundle.putFloat(BundleKey.PARALLAX_SPEED, mSpeedVal); 40 | if (view.getId() == R.id.btn_yahoo_effect){ 41 | Intent intent = new Intent(MainActivity.this, YahooParallaxActivity.class); 42 | intent.putExtra(BundleKey.TYPE_YAHOO, bundle); 43 | startActivity(intent); 44 | }else if (view.getId() == R.id.btn_normal_effect){ 45 | Intent intent = new Intent(MainActivity.this, NormalParallaxActivity.class); 46 | bundle.putFloat(BundleKey.PARALLAX_DISTANCE, mDistanceVal); 47 | intent.putExtra(BundleKey.TYPE_NORMAL, bundle); 48 | startActivity(intent); 49 | } 50 | } 51 | 52 | @Override 53 | public void onProgressChanged(SeekBar seekBar, int i, boolean b) { 54 | Log.d(TAG,"seek val "+i); 55 | if (seekBar.getId() == R.id.distance_seekbar){ 56 | mDistanceVal = 1-i/100f; 57 | Log.d(TAG,"distance " + mDistanceVal); 58 | }else{ 59 | mSpeedVal = i/100f; 60 | Log.d(TAG,"speed "+mSpeedVal); 61 | } 62 | } 63 | 64 | @Override 65 | public void onStartTrackingTouch(SeekBar seekBar) { 66 | 67 | } 68 | 69 | @Override 70 | public void onStopTrackingTouch(SeekBar seekBar) { 71 | 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /app/src/main/java/com/lvable/parallaxeffectdemo/NormalParallaxActivity.java: -------------------------------------------------------------------------------- 1 | package com.lvable.parallaxeffectdemo; 2 | 3 | import android.os.Build; 4 | import android.support.v4.view.PagerAdapter; 5 | import android.support.v4.view.ViewPager; 6 | import android.support.v7.app.ActionBarActivity; 7 | import android.os.Bundle; 8 | import android.view.View; 9 | import android.view.WindowManager; 10 | 11 | 12 | public class NormalParallaxActivity extends ActionBarActivity { 13 | 14 | private ViewPager mPager; 15 | private PagerAdapter mPagerAdapter; 16 | 17 | @Override 18 | protected void onCreate(Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | setContentView(R.layout.activity_normal_parallax); 21 | 22 | Bundle bundle = getIntent().getBundleExtra(BundleKey.TYPE_NORMAL); 23 | float speed = bundle.getFloat(BundleKey.PARALLAX_SPEED); 24 | float distance = bundle.getFloat(BundleKey.PARALLAX_DISTANCE); 25 | 26 | mPager = (ViewPager) findViewById(R.id.pager); 27 | mPagerAdapter = new SlidePagerAdapter(getSupportFragmentManager() 28 | , MainActivity.TYPE.NORMAL_TYPE); 29 | mPager.setAdapter(mPagerAdapter); 30 | int[] resId = {R.id.title_big,R.id.iv_icon,R.id.small_title}; 31 | mPager.setPageTransformer(true, new ParallaxTransformer(speed, distance, resId, false)); 32 | } 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/lvable/parallaxeffectdemo/NormalSlidePageFragment.java: -------------------------------------------------------------------------------- 1 | package com.lvable.parallaxeffectdemo; 2 | 3 | import android.os.Bundle; 4 | import android.support.v4.app.Fragment; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | 10 | /** 11 | * Created by Jiaqi Ning on 4/5/2015. 12 | */ 13 | public class NormalSlidePageFragment extends Fragment { 14 | private ImageView mIconView; 15 | 16 | @Override 17 | public View onCreateView(LayoutInflater inflater, ViewGroup container 18 | , Bundle savedInstanceState) { 19 | ViewGroup rootView = (ViewGroup) inflater.inflate( 20 | R.layout.normal_slide_page, container, false); 21 | mIconView = (ImageView)rootView.findViewById(R.id.iv_icon); 22 | 23 | int index = getArguments().getInt(BundleKey.PAGE_INDEX,0); 24 | switch (index){ 25 | case 1: 26 | rootView.setBackgroundResource(R.drawable.p2); 27 | mIconView.setImageResource(R.drawable.icon2); 28 | break; 29 | case 2: 30 | rootView.setBackgroundResource(R.drawable.p3); 31 | mIconView.setImageResource(R.drawable.icon3); 32 | break; 33 | } 34 | return rootView; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/lvable/parallaxeffectdemo/ParallaxTransformer.java: -------------------------------------------------------------------------------- 1 | package com.lvable.parallaxeffectdemo; 2 | 3 | import android.support.v4.view.ViewPager; 4 | import android.view.View; 5 | 6 | /** 7 | * Created by Jiaqi Ning on 28/4/2015. 8 | */ 9 | public class ParallaxTransformer implements ViewPager.PageTransformer { 10 | private int[] resIds; 11 | private float speedEffect; 12 | private float distanceEffect; 13 | 14 | /** 15 | * The parallax effect PageTransformer 16 | * @param speed the parallax effect common move speed 17 | * @param viewDistance the object`s view view distance(景深) 18 | * @param resIds view`s res id that will have parallax effect 19 | * @param isSpeedReverse moving forward or backward 20 | * */ 21 | public ParallaxTransformer(float speed,float viewDistance, 22 | int[] resIds,boolean isSpeedReverse){ 23 | this.resIds = resIds; 24 | this.speedEffect = speed; 25 | this.distanceEffect = viewDistance; 26 | if (isSpeedReverse) 27 | this.speedEffect *= -1; 28 | } 29 | @Override 30 | public void transformPage(View page, float position) { 31 | 32 | float moveLength = page.getWidth() * speedEffect; 33 | for (int i = 0;i < resIds.length; i++){ 34 | View view = page.findViewById(resIds[i]); 35 | if (view != null){ 36 | view.setTranslationX(moveLength * position); 37 | } 38 | moveLength *= distanceEffect; 39 | } 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/lvable/parallaxeffectdemo/SlidePagerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.lvable.parallaxeffectdemo; 2 | 3 | import android.os.Bundle; 4 | import android.support.v4.app.Fragment; 5 | import android.support.v4.app.FragmentManager; 6 | import android.support.v4.app.FragmentStatePagerAdapter; 7 | 8 | /** 9 | * Created by Jiaqi Ning on 4/5/2015. 10 | */ 11 | public class SlidePagerAdapter extends FragmentStatePagerAdapter { 12 | MainActivity.TYPE mPageType; 13 | private static final int TOTAL_PAGE_COUNT = 3; 14 | 15 | public SlidePagerAdapter(FragmentManager fm, MainActivity.TYPE type) { 16 | super(fm); 17 | mPageType = type; 18 | } 19 | 20 | 21 | @Override 22 | public Fragment getItem(int i) { 23 | Bundle bundle = new Bundle(); 24 | bundle.putInt(BundleKey.PAGE_INDEX, i); 25 | if (mPageType == MainActivity.TYPE.YAHOO_TYPE){ 26 | Fragment fragment = new YahooSlidePageFragment(); 27 | fragment.setArguments(bundle); 28 | return fragment; 29 | }else { 30 | Fragment fragment = new NormalSlidePageFragment(); 31 | fragment.setArguments(bundle); 32 | return fragment; 33 | } 34 | 35 | } 36 | 37 | @Override 38 | public int getCount() { 39 | return TOTAL_PAGE_COUNT; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/com/lvable/parallaxeffectdemo/YahooParallaxActivity.java: -------------------------------------------------------------------------------- 1 | package com.lvable.parallaxeffectdemo; 2 | 3 | import android.os.Build; 4 | import android.support.v4.view.PagerAdapter; 5 | import android.support.v4.view.ViewPager; 6 | import android.support.v7.app.ActionBarActivity; 7 | import android.os.Bundle; 8 | import android.support.v7.widget.Toolbar; 9 | import android.view.Menu; 10 | import android.view.Window; 11 | import android.view.WindowManager; 12 | 13 | 14 | public class YahooParallaxActivity extends ActionBarActivity { 15 | 16 | private ViewPager mPager; 17 | private PagerAdapter mPagerAdapter; 18 | 19 | @Override 20 | protected void onCreate(Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | setContentView(R.layout.activity_yahoo_parallax); 23 | 24 | setupToolbar(); 25 | handleStatusBar(); 26 | 27 | Bundle bundle = getIntent().getBundleExtra(BundleKey.TYPE_YAHOO); 28 | float speed = bundle.getFloat(BundleKey.PARALLAX_SPEED); 29 | 30 | mPager = (ViewPager) findViewById(R.id.pager); 31 | mPagerAdapter = new SlidePagerAdapter(getSupportFragmentManager(), MainActivity.TYPE.YAHOO_TYPE); 32 | mPager.setAdapter(mPagerAdapter); 33 | int[] resId = {R.id.cover_img}; 34 | mPager.setPageTransformer(true, new ParallaxTransformer(speed, 0, resId, true)); 35 | } 36 | 37 | /**Hide the status bar on pre-19 android 38 | * Set the status bar to transparent after version 19 */ 39 | private void handleStatusBar() { 40 | if (Build.VERSION.SDK_INT < 19) { 41 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 42 | WindowManager.LayoutParams.FLAG_FULLSCREEN); 43 | }else { 44 | Window w = getWindow(); 45 | w.setFlags( 46 | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, 47 | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 48 | 49 | } 50 | } 51 | 52 | private void setupToolbar() { 53 | Toolbar toolbar = (Toolbar)findViewById(R.id.my_toolbar); 54 | setSupportActionBar(toolbar); 55 | getSupportActionBar().setDisplayShowTitleEnabled(false); 56 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 57 | getSupportActionBar().setDisplayShowHomeEnabled(true); 58 | toolbar.setPadding(0, getStatusBarHeight(), 0, 0); 59 | } 60 | 61 | public int getStatusBarHeight() { 62 | int result = 0; 63 | int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android"); 64 | if (resourceId > 0) { 65 | result = getResources().getDimensionPixelSize(resourceId); 66 | } 67 | return result; 68 | } 69 | 70 | @Override 71 | public boolean onCreateOptionsMenu(Menu menu) { 72 | getMenuInflater().inflate(R.menu.menu_yahoo_parallax, menu); 73 | return true; 74 | } 75 | 76 | 77 | 78 | } 79 | -------------------------------------------------------------------------------- /app/src/main/java/com/lvable/parallaxeffectdemo/YahooSlidePageFragment.java: -------------------------------------------------------------------------------- 1 | package com.lvable.parallaxeffectdemo; 2 | 3 | import android.os.Build; 4 | import android.os.Bundle; 5 | import android.support.v4.app.Fragment; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.view.ViewTreeObserver; 10 | import android.widget.ImageView; 11 | import android.widget.ScrollView; 12 | 13 | import com.lvable.parallaxeffectdemo.view.NotifyingScrollView; 14 | 15 | /** 16 | * Created by Jiaqi Ning on 4/5/2015. 17 | */ 18 | public class YahooSlidePageFragment extends Fragment { 19 | 20 | private ImageView mCoverImageView; 21 | private int mCoverImageHeight; 22 | private float mVerticalParalllaxSpeed = 0.3f; 23 | 24 | @Override 25 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 26 | Bundle savedInstanceState) { 27 | ViewGroup rootView = (ViewGroup) inflater.inflate( 28 | R.layout.yahoo_page, container, false); 29 | ((NotifyingScrollView) rootView.findViewById(R.id.scroll_view)) 30 | .setOnScrollChangedListener(mOnScrollChangedListener); 31 | mCoverImageView = (ImageView) rootView.findViewById(R.id.cover_img); 32 | 33 | int index = getArguments().getInt(BundleKey.PAGE_INDEX,0); 34 | switch (index){ 35 | case 1: 36 | mCoverImageView.setImageResource(R.drawable.p2); 37 | break; 38 | case 2: 39 | mCoverImageView.setImageResource(R.drawable.p3); 40 | break; 41 | } 42 | 43 | ViewTreeObserver obs = mCoverImageView.getViewTreeObserver(); 44 | obs.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { 45 | @Override 46 | public void onGlobalLayout() { 47 | mCoverImageHeight = mCoverImageView.getHeight(); 48 | ViewTreeObserver obs = mCoverImageView.getViewTreeObserver(); 49 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 50 | obs.removeOnGlobalLayoutListener(this); 51 | } else { 52 | obs.removeGlobalOnLayoutListener(this); 53 | } 54 | } 55 | }); 56 | 57 | return rootView; 58 | } 59 | private NotifyingScrollView.OnScrollChangedListener mOnScrollChangedListener 60 | = new NotifyingScrollView.OnScrollChangedListener() { 61 | public void onScrollChanged(ScrollView who, int l, int t, int oldl, int oldt) { 62 | if (l < mCoverImageHeight){ 63 | final float ratio = 64 | (float) Math.min(Math.max(t, 0), mCoverImageHeight) / mCoverImageHeight; 65 | mCoverImageView.setTranslationY(ratio* mCoverImageHeight * mVerticalParalllaxSpeed); 66 | } 67 | } 68 | }; 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/lvable/parallaxeffectdemo/view/NotifyingScrollView.java: -------------------------------------------------------------------------------- 1 | package com.lvable.parallaxeffectdemo.view; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.ScrollView; 6 | 7 | /** 8 | * @author Cyril Mottier 9 | */ 10 | public class NotifyingScrollView extends ScrollView { 11 | /** 12 | * The Scrollview scroll position listener*/ 13 | public interface OnScrollChangedListener { 14 | /*** 15 | * @param who the view that perform scroll 16 | * @param l Current horizontal scroll origin. 17 | * @param t Current vertical scroll origin. 18 | * @param oldl Previous horizontal scroll origin. 19 | * @param oldt Previous vertical scroll origin. 20 | */ 21 | void onScrollChanged(ScrollView who, int l, int t, int oldl, int oldt); 22 | } 23 | private OnScrollChangedListener mOnScrollChangedListener; 24 | 25 | public NotifyingScrollView(Context context) { 26 | super(context); 27 | } 28 | public NotifyingScrollView(Context context, AttributeSet attrs) { 29 | super(context, attrs); 30 | } 31 | 32 | public NotifyingScrollView(Context context, AttributeSet attrs, int defStyleAttr) { 33 | super(context, attrs, defStyleAttr); 34 | } 35 | 36 | 37 | public void setOnScrollChangedListener(OnScrollChangedListener listener) { 38 | mOnScrollChangedListener = listener; 39 | } 40 | 41 | @Override 42 | protected void onScrollChanged(int l, int t, int oldl, int oldt) { 43 | super.onScrollChanged(l, t, oldl, oldt); 44 | if (mOnScrollChangedListener != null) { 45 | mOnScrollChangedListener.onScrollChanged(this, l, t, oldl, oldt); 46 | } 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/lvable/parallaxeffectdemo/view/SharpRectView.java: -------------------------------------------------------------------------------- 1 | package com.lvable.parallaxeffectdemo.view; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.Paint; 7 | import android.graphics.Path; 8 | import android.util.AttributeSet; 9 | import android.view.View; 10 | 11 | import com.lvable.parallaxeffectdemo.R; 12 | 13 | /** 14 | * Created by Jiaqi Ning on 28/4/2015. 15 | */ 16 | public class SharpRectView extends View { 17 | private Paint mPaint; 18 | private Path mPath; 19 | public SharpRectView(Context context) { 20 | super(context); 21 | init(); 22 | } 23 | 24 | public SharpRectView(Context context, AttributeSet attrs) { 25 | super(context, attrs); 26 | init(); 27 | } 28 | 29 | public SharpRectView(Context context, AttributeSet attrs, int defStyleAttr) { 30 | super(context, attrs, defStyleAttr); 31 | init(); 32 | } 33 | 34 | private void init() { 35 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 36 | mPaint.setStyle(Paint.Style.FILL_AND_STROKE); 37 | mPaint.setColor(getResources().getColor(R.color.comfort_white)); 38 | mPath = new Path(); 39 | } 40 | 41 | @Override 42 | protected void onDraw(Canvas canvas) { 43 | float width = getWidth(); 44 | float height = getHeight(); 45 | mPath.reset(); 46 | mPath.moveTo(0,0); 47 | mPath.lineTo(width, 0.26f * width); 48 | mPath.lineTo(width, height); 49 | mPath.lineTo(0, height); 50 | mPath.lineTo(0, 0); 51 | mPath.close(); 52 | canvas.drawPath(mPath,mPaint); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_share_variant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qianlvable/ParallaxEffectDemo/e406eb9bd3b8815dc87a6c63883586ca621295f5/app/src/main/res/drawable/ic_share_variant.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/icon1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qianlvable/ParallaxEffectDemo/e406eb9bd3b8815dc87a6c63883586ca621295f5/app/src/main/res/drawable/icon1.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/icon2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qianlvable/ParallaxEffectDemo/e406eb9bd3b8815dc87a6c63883586ca621295f5/app/src/main/res/drawable/icon2.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/icon3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qianlvable/ParallaxEffectDemo/e406eb9bd3b8815dc87a6c63883586ca621295f5/app/src/main/res/drawable/icon3.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/p1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qianlvable/ParallaxEffectDemo/e406eb9bd3b8815dc87a6c63883586ca621295f5/app/src/main/res/drawable/p1.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/p2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qianlvable/ParallaxEffectDemo/e406eb9bd3b8815dc87a6c63883586ca621295f5/app/src/main/res/drawable/p2.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/p3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qianlvable/ParallaxEffectDemo/e406eb9bd3b8815dc87a6c63883586ca621295f5/app/src/main/res/drawable/p3.jpg -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 10 | 11 |