├── README.md ├── android-page-transition ├── .gitignore ├── app │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── stone │ │ │ └── transition │ │ │ └── ApplicationTest.java │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── assets │ │ │ ├── image1.jpg │ │ │ ├── image2.jpg │ │ │ ├── image3.jpg │ │ │ ├── image4.jpg │ │ │ └── image5.jpg │ │ ├── java │ │ │ └── com │ │ │ │ └── stone │ │ │ │ └── transition │ │ │ │ ├── AspectRatioCardView.java │ │ │ │ ├── CommonFragment.java │ │ │ │ ├── CustPagerTransformer.java │ │ │ │ ├── DetailActivity.java │ │ │ │ ├── DragLayout.java │ │ │ │ └── MainActivity.java │ │ └── res │ │ │ ├── drawable-xxhdpi │ │ │ ├── background.jpg │ │ │ ├── close.png │ │ │ ├── gps.png │ │ │ ├── head1.png │ │ │ ├── head2.png │ │ │ ├── head3.png │ │ │ ├── head4.png │ │ │ ├── icon1.png │ │ │ ├── icon2.png │ │ │ ├── icon3.png │ │ │ ├── like.png │ │ │ ├── paper_background.png │ │ │ ├── search.png │ │ │ ├── three_dot.png │ │ │ └── white_back.9.png │ │ │ ├── layout │ │ │ ├── activity_detail.xml │ │ │ ├── activity_main.xml │ │ │ ├── detail_list_item.xml │ │ │ └── fragment_common.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── values-v21 │ │ │ └── styles.xml │ │ │ ├── values-w820dp │ │ │ └── dimens.xml │ │ │ └── values │ │ │ ├── attrs.xml │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ └── test │ │ └── java │ │ └── com │ │ └── stone │ │ └── transition │ │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle ├── capture1.jpg ├── gif1.gif ├── gif2.gif ├── gif3.gif └── pageTransition.apk /README.md: -------------------------------------------------------------------------------- 1 | # android-page-transition 2 | viewpager with vertical sliding effects and activity transition
3 | 4 |

5 | Drawing 6 |
7 | 8 |

9 | The original design is here: https://dribbble.com/shots/2493845-ToFind-Transition-Test 10 | 11 | #### Captured images: 12 | 13 | 14 | 15 | 16 | #### Coding design 17 | Sliding pages to the left or right, as we know, could be implemented by using ViewPager. And fortunately, ViewPager's PagerTransformer is allowed for customization. That's to say, [CustPagerTransformer](android-page-transition/app/src/main/java/com/stone/transition/CustPagerTransformer.java) could get rid of all the parallax effects.
18 | Then, in viewpager's fragment item, vertical slide is an independent module, which could be realized by using ViewDragHelper. In the activity transition part, android OS (above 5.0) makes it easy to transfer to another activity.
19 | 20 | #### Thanks 21 | [rubensousa/ViewPagerCards](https://github.com/rubensousa/ViewPagerCards)
22 | [antoniolg/MaterialEverywhere](https://github.com/antoniolg/MaterialEverywhere) 23 | 24 | #### Demo Apk 25 | [download](https://github.com/xmuSistone/android-page-transition/blob/master/pageTransition.apk?raw=true) 26 | 27 | ### Version: 1.0 28 | 29 | * Pilot version 30 | 31 | ## License 32 | 33 | Copyright 2016, xmuSistone 34 | 35 | Licensed under the Apache License, Version 2.0 (the "License"); 36 | you may not use this file except in compliance with the License. 37 | You may obtain a copy of the License at 38 | 39 | http://www.apache.org/licenses/LICENSE-2.0 40 | 41 | Unless required by applicable law or agreed to in writing, software 42 | distributed under the License is distributed on an "AS IS" BASIS, 43 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 44 | See the License for the specific language governing permissions and 45 | limitations under the License. 46 | 47 | 48 | 49 | [1]: http://square.github.com/dagger/ 50 | 51 | -------------------------------------------------------------------------------- /android-page-transition/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /android-page-transition/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /android-page-transition/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.2" 6 | 7 | defaultConfig { 8 | applicationId "com.stone.transition" 9 | minSdkVersion 14 10 | targetSdkVersion 23 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 | testCompile 'junit:junit:4.12' 25 | compile 'com.android.support:appcompat-v7:23.2.0' 26 | compile 'com.android.support:cardview-v7:23.2.0' 27 | compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5' 28 | } 29 | -------------------------------------------------------------------------------- /android-page-transition/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 D:\adt-bundle-windows-x86-20130917\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 | -------------------------------------------------------------------------------- /android-page-transition/app/src/androidTest/java/com/stone/transition/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.stone.transition; 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 | } -------------------------------------------------------------------------------- /android-page-transition/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /android-page-transition/app/src/main/assets/image1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmuSistone/ViewpagerTransition/fa92d8296dbf22e4daef0fd2de7b35a587625ed9/android-page-transition/app/src/main/assets/image1.jpg -------------------------------------------------------------------------------- /android-page-transition/app/src/main/assets/image2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmuSistone/ViewpagerTransition/fa92d8296dbf22e4daef0fd2de7b35a587625ed9/android-page-transition/app/src/main/assets/image2.jpg -------------------------------------------------------------------------------- /android-page-transition/app/src/main/assets/image3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmuSistone/ViewpagerTransition/fa92d8296dbf22e4daef0fd2de7b35a587625ed9/android-page-transition/app/src/main/assets/image3.jpg -------------------------------------------------------------------------------- /android-page-transition/app/src/main/assets/image4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmuSistone/ViewpagerTransition/fa92d8296dbf22e4daef0fd2de7b35a587625ed9/android-page-transition/app/src/main/assets/image4.jpg -------------------------------------------------------------------------------- /android-page-transition/app/src/main/assets/image5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmuSistone/ViewpagerTransition/fa92d8296dbf22e4daef0fd2de7b35a587625ed9/android-page-transition/app/src/main/assets/image5.jpg -------------------------------------------------------------------------------- /android-page-transition/app/src/main/java/com/stone/transition/AspectRatioCardView.java: -------------------------------------------------------------------------------- 1 | package com.stone.transition; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.CardView; 5 | import android.util.AttributeSet; 6 | import android.view.ViewGroup; 7 | 8 | /** 9 | * 锁定宽高比的CardView 10 | * Created by xmuSistone on 2016/9/21. 11 | */ 12 | public class AspectRatioCardView extends CardView { 13 | 14 | private float ratio = 1.2f; 15 | 16 | public AspectRatioCardView(Context context) { 17 | this(context, null); 18 | } 19 | 20 | public AspectRatioCardView(Context context, AttributeSet attrs) { 21 | this(context, attrs, 0); 22 | } 23 | 24 | public AspectRatioCardView(Context context, AttributeSet attrs, int defStyleAttr) { 25 | super(context, attrs, defStyleAttr); 26 | } 27 | 28 | @Override 29 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 30 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 31 | if (ratio > 0) { 32 | int ratioHeight = (int) (getMeasuredWidth() * ratio); 33 | setMeasuredDimension(getMeasuredWidth(), ratioHeight); 34 | ViewGroup.LayoutParams lp = getLayoutParams(); 35 | lp.height = ratioHeight; 36 | setLayoutParams(lp); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /android-page-transition/app/src/main/java/com/stone/transition/CommonFragment.java: -------------------------------------------------------------------------------- 1 | package com.stone.transition; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.support.annotation.Nullable; 7 | import android.support.v4.app.ActivityCompat; 8 | import android.support.v4.app.ActivityOptionsCompat; 9 | import android.support.v4.app.Fragment; 10 | import android.support.v4.util.Pair; 11 | import android.view.LayoutInflater; 12 | import android.view.View; 13 | import android.view.ViewGroup; 14 | import android.widget.ImageView; 15 | import android.widget.RatingBar; 16 | 17 | import com.nostra13.universalimageloader.core.ImageLoader; 18 | 19 | /** 20 | * Created by xmuSistone on 2016/9/18. 21 | */ 22 | public class CommonFragment extends Fragment implements DragLayout.GotoDetailListener { 23 | private ImageView imageView; 24 | private View address1, address2, address3, address4, address5; 25 | private RatingBar ratingBar; 26 | private View head1, head2, head3, head4; 27 | private String imageUrl; 28 | 29 | @Nullable 30 | @Override 31 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 32 | View rootView = inflater.inflate(R.layout.fragment_common, null); 33 | DragLayout dragLayout = (DragLayout) rootView.findViewById(R.id.drag_layout); 34 | imageView = (ImageView) dragLayout.findViewById(R.id.image); 35 | ImageLoader.getInstance().displayImage(imageUrl, imageView); 36 | address1 = dragLayout.findViewById(R.id.address1); 37 | address2 = dragLayout.findViewById(R.id.address2); 38 | address3 = dragLayout.findViewById(R.id.address3); 39 | address4 = dragLayout.findViewById(R.id.address4); 40 | address5 = dragLayout.findViewById(R.id.address5); 41 | ratingBar = (RatingBar) dragLayout.findViewById(R.id.rating); 42 | 43 | head1 = dragLayout.findViewById(R.id.head1); 44 | head2 = dragLayout.findViewById(R.id.head2); 45 | head3 = dragLayout.findViewById(R.id.head3); 46 | head4 = dragLayout.findViewById(R.id.head4); 47 | 48 | dragLayout.setGotoDetailListener(this); 49 | return rootView; 50 | } 51 | 52 | @Override 53 | public void gotoDetail() { 54 | Activity activity = (Activity) getContext(); 55 | ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(activity, 56 | new Pair(imageView, DetailActivity.IMAGE_TRANSITION_NAME), 57 | new Pair(address1, DetailActivity.ADDRESS1_TRANSITION_NAME), 58 | new Pair(address2, DetailActivity.ADDRESS2_TRANSITION_NAME), 59 | new Pair(address3, DetailActivity.ADDRESS3_TRANSITION_NAME), 60 | new Pair(address4, DetailActivity.ADDRESS4_TRANSITION_NAME), 61 | new Pair(address5, DetailActivity.ADDRESS5_TRANSITION_NAME), 62 | new Pair(ratingBar, DetailActivity.RATINGBAR_TRANSITION_NAME), 63 | new Pair(head1, DetailActivity.HEAD1_TRANSITION_NAME), 64 | new Pair(head2, DetailActivity.HEAD2_TRANSITION_NAME), 65 | new Pair(head3, DetailActivity.HEAD3_TRANSITION_NAME), 66 | new Pair(head4, DetailActivity.HEAD4_TRANSITION_NAME) 67 | ); 68 | Intent intent = new Intent(activity, DetailActivity.class); 69 | intent.putExtra(DetailActivity.EXTRA_IMAGE_URL, imageUrl); 70 | ActivityCompat.startActivity(activity, intent, options.toBundle()); 71 | } 72 | 73 | public void bindData(String imageUrl) { 74 | this.imageUrl = imageUrl; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /android-page-transition/app/src/main/java/com/stone/transition/CustPagerTransformer.java: -------------------------------------------------------------------------------- 1 | package com.stone.transition; 2 | 3 | import android.content.Context; 4 | import android.support.v4.view.ViewPager; 5 | import android.view.View; 6 | 7 | /** 8 | * 实现ViewPager左右滑动时的时差 9 | * Created by xmuSistone on 2016/9/18. 10 | */ 11 | public class CustPagerTransformer implements ViewPager.PageTransformer { 12 | 13 | private int maxTranslateOffsetX; 14 | private ViewPager viewPager; 15 | 16 | public CustPagerTransformer(Context context) { 17 | this.maxTranslateOffsetX = dp2px(context, 180); 18 | } 19 | 20 | public void transformPage(View view, float position) { 21 | if (viewPager == null) { 22 | viewPager = (ViewPager) view.getParent(); 23 | } 24 | 25 | int leftInScreen = view.getLeft() - viewPager.getScrollX(); 26 | int centerXInViewPager = leftInScreen + view.getMeasuredWidth() / 2; 27 | int offsetX = centerXInViewPager - viewPager.getMeasuredWidth() / 2; 28 | float offsetRate = (float) offsetX * 0.38f / viewPager.getMeasuredWidth(); 29 | float scaleFactor = 1 - Math.abs(offsetRate); 30 | if (scaleFactor > 0) { 31 | view.setScaleX(scaleFactor); 32 | view.setScaleY(scaleFactor); 33 | view.setTranslationX(-maxTranslateOffsetX * offsetRate); 34 | } 35 | } 36 | 37 | /** 38 | * dp和像素转换 39 | */ 40 | private int dp2px(Context context, float dipValue) { 41 | float m = context.getResources().getDisplayMetrics().density; 42 | return (int) (dipValue * m + 0.5f); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /android-page-transition/app/src/main/java/com/stone/transition/DetailActivity.java: -------------------------------------------------------------------------------- 1 | package com.stone.transition; 2 | 3 | import android.os.Build; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.FragmentActivity; 7 | import android.support.v4.view.ViewCompat; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.Window; 11 | import android.view.WindowManager; 12 | import android.widget.ImageView; 13 | import android.widget.LinearLayout; 14 | import android.widget.RatingBar; 15 | 16 | import com.nostra13.universalimageloader.core.ImageLoader; 17 | 18 | /** 19 | * Created by xmuSistone on 2016/9/19. 20 | */ 21 | public class DetailActivity extends FragmentActivity { 22 | 23 | public static final String EXTRA_IMAGE_URL = "detailImageUrl"; 24 | 25 | public static final String IMAGE_TRANSITION_NAME = "transitionImage"; 26 | public static final String ADDRESS1_TRANSITION_NAME = "address1"; 27 | public static final String ADDRESS2_TRANSITION_NAME = "address2"; 28 | public static final String ADDRESS3_TRANSITION_NAME = "address3"; 29 | public static final String ADDRESS4_TRANSITION_NAME = "address4"; 30 | public static final String ADDRESS5_TRANSITION_NAME = "address5"; 31 | public static final String RATINGBAR_TRANSITION_NAME = "ratingBar"; 32 | 33 | public static final String HEAD1_TRANSITION_NAME = "head1"; 34 | public static final String HEAD2_TRANSITION_NAME = "head2"; 35 | public static final String HEAD3_TRANSITION_NAME = "head3"; 36 | public static final String HEAD4_TRANSITION_NAME = "head4"; 37 | 38 | private View address1, address2, address3, address4, address5; 39 | private ImageView imageView; 40 | private RatingBar ratingBar; 41 | 42 | private LinearLayout listContainer; 43 | private static final String[] headStrs = {HEAD1_TRANSITION_NAME, HEAD2_TRANSITION_NAME, HEAD3_TRANSITION_NAME, HEAD4_TRANSITION_NAME}; 44 | private static final int[] imageIds = {R.drawable.head1, R.drawable.head2, R.drawable.head3, R.drawable.head4}; 45 | 46 | @Override 47 | protected void onCreate(@Nullable Bundle savedInstanceState) { 48 | super.onCreate(savedInstanceState); 49 | setContentView(R.layout.activity_detail); 50 | 51 | imageView = (ImageView) findViewById(R.id.image); 52 | address1 = findViewById(R.id.address1); 53 | address2 = findViewById(R.id.address2); 54 | address3 = findViewById(R.id.address3); 55 | address4 = findViewById(R.id.address4); 56 | address5 = findViewById(R.id.address5); 57 | ratingBar = (RatingBar) findViewById(R.id.rating); 58 | listContainer = (LinearLayout) findViewById(R.id.detail_list_container); 59 | 60 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 61 | Window window = getWindow(); 62 | window.setFlags( 63 | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, 64 | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 65 | } 66 | 67 | String imageUrl = getIntent().getStringExtra(EXTRA_IMAGE_URL); 68 | ImageLoader.getInstance().displayImage(imageUrl, imageView); 69 | 70 | ViewCompat.setTransitionName(imageView, IMAGE_TRANSITION_NAME); 71 | ViewCompat.setTransitionName(address1, ADDRESS1_TRANSITION_NAME); 72 | ViewCompat.setTransitionName(address2, ADDRESS2_TRANSITION_NAME); 73 | ViewCompat.setTransitionName(address3, ADDRESS3_TRANSITION_NAME); 74 | ViewCompat.setTransitionName(address4, ADDRESS4_TRANSITION_NAME); 75 | ViewCompat.setTransitionName(address5, ADDRESS5_TRANSITION_NAME); 76 | ViewCompat.setTransitionName(ratingBar, RATINGBAR_TRANSITION_NAME); 77 | 78 | dealListView(); 79 | } 80 | 81 | private void dealListView() { 82 | LayoutInflater layoutInflater = LayoutInflater.from(this); 83 | 84 | for (int i = 0; i < 20; i++) { 85 | View childView = layoutInflater.inflate(R.layout.detail_list_item, null); 86 | listContainer.addView(childView); 87 | ImageView headView = (ImageView) childView.findViewById(R.id.head); 88 | if (i < headStrs.length) { 89 | headView.setImageResource(imageIds[i % imageIds.length]); 90 | ViewCompat.setTransitionName(headView, headStrs[i]); 91 | } 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /android-page-transition/app/src/main/java/com/stone/transition/DragLayout.java: -------------------------------------------------------------------------------- 1 | package com.stone.transition; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.support.v4.view.GestureDetectorCompat; 6 | import android.support.v4.view.ViewCompat; 7 | import android.support.v4.widget.ViewDragHelper; 8 | import android.util.AttributeSet; 9 | import android.view.GestureDetector; 10 | import android.view.MotionEvent; 11 | import android.view.View; 12 | import android.view.ViewConfiguration; 13 | import android.widget.FrameLayout; 14 | 15 | /** 16 | * 尽量考虑了所有操作系统版本的分辨率适配 17 | * Created by xmuSistone on 2016/9/18. 18 | */ 19 | public class DragLayout extends FrameLayout { 20 | 21 | private int bottomDragVisibleHeight; // 滑动可见的高度 22 | private int bototmExtraIndicatorHeight; // 底部指示器的高度 23 | private int dragTopDest = 0; // 顶部View滑动的目标位置 24 | private static final int DECELERATE_THRESHOLD = 120; 25 | private static final int DRAG_SWITCH_DISTANCE_THRESHOLD = 100; 26 | private static final int DRAG_SWITCH_VEL_THRESHOLD = 800; 27 | 28 | private static final float MIN_SCALE_RATIO = 0.5f; 29 | private static final float MAX_SCALE_RATIO = 1.0f; 30 | 31 | private static final int STATE_CLOSE = 1; 32 | private static final int STATE_EXPANDED = 2; 33 | private int downState; // 按下时的状态 34 | 35 | private final ViewDragHelper mDragHelper; 36 | private final GestureDetectorCompat moveDetector; 37 | private int mTouchSlop = 5; // 判定为滑动的阈值,单位是像素 38 | private int originX, originY; // 初始状态下,topView的坐标 39 | private View bottomView, topView; // FrameLayout的两个子View 40 | 41 | private GotoDetailListener gotoDetailListener; 42 | 43 | public DragLayout(Context context) { 44 | this(context, null); 45 | } 46 | 47 | public DragLayout(Context context, AttributeSet attrs) { 48 | this(context, attrs, 0); 49 | } 50 | 51 | public DragLayout(Context context, AttributeSet attrs, int defStyleAttr) { 52 | super(context, attrs, defStyleAttr); 53 | 54 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.app, 0, 0); 55 | bottomDragVisibleHeight = (int) a.getDimension(R.styleable.app_bottomDragVisibleHeight, 0); 56 | bototmExtraIndicatorHeight = (int) a.getDimension(R.styleable.app_bototmExtraIndicatorHeight, 0); 57 | a.recycle(); 58 | 59 | mDragHelper = ViewDragHelper 60 | .create(this, 10f, new DragHelperCallback()); 61 | mDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_TOP); 62 | moveDetector = new GestureDetectorCompat(context, new MoveDetector()); 63 | moveDetector.setIsLongpressEnabled(false); // 不处理长按事件 64 | 65 | // 滑动的距离阈值由系统提供 66 | ViewConfiguration configuration = ViewConfiguration.get(getContext()); 67 | mTouchSlop = configuration.getScaledTouchSlop(); 68 | } 69 | 70 | @Override 71 | protected void onFinishInflate() { 72 | super.onFinishInflate(); 73 | bottomView = getChildAt(0); 74 | topView = getChildAt(1); 75 | 76 | topView.setOnClickListener(new View.OnClickListener() { 77 | @Override 78 | public void onClick(View v) { 79 | // 点击回调 80 | int state = getCurrentState(); 81 | if (state == STATE_CLOSE) { 82 | // 点击时为初始状态,需要展开 83 | if (mDragHelper.smoothSlideViewTo(topView, originX, dragTopDest)) { 84 | ViewCompat.postInvalidateOnAnimation(DragLayout.this); 85 | } 86 | } else { 87 | // 点击时为展开状态,直接进入详情页 88 | gotoDetailActivity(); 89 | } 90 | } 91 | }); 92 | } 93 | 94 | // 跳转到下一页 95 | private void gotoDetailActivity() { 96 | if (null != gotoDetailListener) { 97 | gotoDetailListener.gotoDetail(); 98 | } 99 | } 100 | 101 | private class DragHelperCallback extends ViewDragHelper.Callback { 102 | 103 | @Override 104 | public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { 105 | if (changedView == topView) { 106 | processLinkageView(); 107 | } 108 | } 109 | 110 | @Override 111 | public boolean tryCaptureView(View child, int pointerId) { 112 | if (child == topView) { 113 | return true; 114 | } 115 | return false; 116 | } 117 | 118 | @Override 119 | public int clampViewPositionVertical(View child, int top, int dy) { 120 | int currentTop = child.getTop(); 121 | if (top > child.getTop()) { 122 | // 往下拉的时候,阻力最小 123 | return currentTop + (top - currentTop) / 2; 124 | } 125 | 126 | int result; 127 | if (currentTop > DECELERATE_THRESHOLD * 3) { 128 | result = currentTop + (top - currentTop) / 2; 129 | } else if (currentTop > DECELERATE_THRESHOLD * 2) { 130 | result = currentTop + (top - currentTop) / 4; 131 | } else if (currentTop > 0) { 132 | result = currentTop + (top - currentTop) / 8; 133 | } else if (currentTop > -DECELERATE_THRESHOLD) { 134 | result = currentTop + (top - currentTop) / 16; 135 | } else if (currentTop > -DECELERATE_THRESHOLD * 2) { 136 | result = currentTop + (top - currentTop) / 32; 137 | } else if (currentTop > -DECELERATE_THRESHOLD * 3) { 138 | result = currentTop + (top - currentTop) / 48; 139 | } else { 140 | result = currentTop + (top - currentTop) / 64; 141 | } 142 | return result; 143 | } 144 | 145 | @Override 146 | public int clampViewPositionHorizontal(View child, int left, int dx) { 147 | return child.getLeft(); 148 | } 149 | 150 | @Override 151 | public int getViewHorizontalDragRange(View child) { 152 | return 600; 153 | } 154 | 155 | @Override 156 | public int getViewVerticalDragRange(View child) { 157 | return 600; 158 | } 159 | 160 | @Override 161 | public void onViewReleased(View releasedChild, float xvel, float yvel) { 162 | int finalY = originY; 163 | if (downState == STATE_CLOSE) { 164 | // 按下的时候,状态为:初始状态 165 | if (originY - releasedChild.getTop() > DRAG_SWITCH_DISTANCE_THRESHOLD || yvel < -DRAG_SWITCH_VEL_THRESHOLD) { 166 | finalY = dragTopDest; 167 | } 168 | } else { 169 | // 按下的时候,状态为:展开状态 170 | boolean gotoBottom = releasedChild.getTop() - dragTopDest > DRAG_SWITCH_DISTANCE_THRESHOLD || yvel > DRAG_SWITCH_VEL_THRESHOLD; 171 | if (!gotoBottom) { 172 | finalY = dragTopDest; 173 | 174 | // 如果按下时已经展开,又向上拖动了,就进入详情页 175 | if (dragTopDest - releasedChild.getTop() > mTouchSlop) { 176 | gotoDetailActivity(); 177 | postResetPosition(); 178 | return; 179 | } 180 | } 181 | } 182 | 183 | if (mDragHelper.smoothSlideViewTo(releasedChild, originX, finalY)) { 184 | ViewCompat.postInvalidateOnAnimation(DragLayout.this); 185 | } 186 | } 187 | } 188 | 189 | 190 | private void postResetPosition() { 191 | this.postDelayed(new Runnable() { 192 | @Override 193 | public void run() { 194 | topView.offsetTopAndBottom(dragTopDest - topView.getTop()); 195 | } 196 | }, 500); 197 | } 198 | 199 | /** 200 | * 顶层ImageView位置变动,需要对底层的view进行缩放显示 201 | */ 202 | private void processLinkageView() { 203 | if (topView.getTop() > originY) { 204 | bottomView.setAlpha(0); 205 | } else { 206 | float alpha = (originY - topView.getTop()) * 0.01f; 207 | if (alpha > 1) { 208 | alpha = 1; 209 | } 210 | bottomView.setAlpha(alpha); 211 | int maxDistance = originY - dragTopDest; 212 | int currentDistance = topView.getTop() - dragTopDest; 213 | float scaleRatio = 1; 214 | float distanceRatio = (float) currentDistance / maxDistance; 215 | if (currentDistance > 0) { 216 | scaleRatio = MIN_SCALE_RATIO + (MAX_SCALE_RATIO - MIN_SCALE_RATIO) * (1 - distanceRatio); 217 | } 218 | bottomView.setScaleX(scaleRatio); 219 | bottomView.setScaleY(scaleRatio); 220 | } 221 | } 222 | 223 | class MoveDetector extends GestureDetector.SimpleOnGestureListener { 224 | @Override 225 | public boolean onScroll(MotionEvent e1, MotionEvent e2, float dx, 226 | float dy) { 227 | // 拖动了,touch不往下传递 228 | return Math.abs(dy) + Math.abs(dx) > mTouchSlop; 229 | } 230 | } 231 | 232 | @Override 233 | public void computeScroll() { 234 | if (mDragHelper.continueSettling(true)) { 235 | ViewCompat.postInvalidateOnAnimation(this); 236 | } 237 | } 238 | 239 | /** 240 | * 获取当前状态 241 | */ 242 | private int getCurrentState() { 243 | int state; 244 | if (Math.abs(topView.getTop() - dragTopDest) <= mTouchSlop) { 245 | state = STATE_EXPANDED; 246 | } else { 247 | state = STATE_CLOSE; 248 | } 249 | return state; 250 | } 251 | 252 | 253 | @Override 254 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 255 | if (!changed) { 256 | return; 257 | } 258 | 259 | super.onLayout(changed, left, top, right, bottom); 260 | 261 | originX = (int) topView.getX(); 262 | originY = (int) topView.getY(); 263 | dragTopDest = bottomView.getBottom() - bottomDragVisibleHeight - topView.getMeasuredHeight(); 264 | } 265 | 266 | /* touch事件的拦截与处理都交给mDraghelper来处理 */ 267 | @Override 268 | public boolean onInterceptTouchEvent(MotionEvent ev) { 269 | // 1. detector和mDragHelper判断是否需要拦截 270 | boolean yScroll = moveDetector.onTouchEvent(ev); 271 | boolean shouldIntercept = false; 272 | try { 273 | shouldIntercept = mDragHelper.shouldInterceptTouchEvent(ev); 274 | } catch (Exception e) { 275 | } 276 | 277 | // 2. 触点按下的时候直接交给mDragHelper 278 | int action = ev.getActionMasked(); 279 | if (action == MotionEvent.ACTION_DOWN) { 280 | downState = getCurrentState(); 281 | mDragHelper.processTouchEvent(ev); 282 | } 283 | 284 | return shouldIntercept && yScroll; 285 | } 286 | 287 | @Override 288 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 289 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 290 | 291 | // bottomMarginTop高度的计算,还是需要有一个清晰的数学模型才可以。 292 | // 实现的效果,是topView.top和bottomView.bottom展开前、与展开后都整体居中 293 | int bottomMarginTop = (bottomDragVisibleHeight + topView.getMeasuredHeight() / 2 - bottomView.getMeasuredHeight() / 2) / 2 - bototmExtraIndicatorHeight; 294 | FrameLayout.LayoutParams lp1 = (LayoutParams) bottomView.getLayoutParams(); 295 | lp1.setMargins(0, bottomMarginTop, 0, 0); 296 | bottomView.setLayoutParams(lp1); 297 | } 298 | 299 | @Override 300 | public boolean onTouchEvent(MotionEvent e) { 301 | // 统一交给mDragHelper处理,由DragHelperCallback实现拖动效果 302 | try { 303 | mDragHelper.processTouchEvent(e); 304 | } catch (Exception ex) { 305 | ex.printStackTrace(); 306 | } 307 | return true; 308 | } 309 | 310 | public void setGotoDetailListener(GotoDetailListener gotoDetailListener) { 311 | this.gotoDetailListener = gotoDetailListener; 312 | } 313 | 314 | public interface GotoDetailListener { 315 | public void gotoDetail(); 316 | } 317 | } 318 | -------------------------------------------------------------------------------- /android-page-transition/app/src/main/java/com/stone/transition/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.stone.transition; 2 | 3 | import android.graphics.Color; 4 | import android.os.Build; 5 | import android.support.v4.app.Fragment; 6 | import android.support.v4.app.FragmentActivity; 7 | import android.support.v4.app.FragmentPagerAdapter; 8 | import android.support.v4.app.FragmentStatePagerAdapter; 9 | import android.support.v4.view.ViewPager; 10 | import android.support.v7.app.AppCompatActivity; 11 | import android.os.Bundle; 12 | import android.text.Html; 13 | import android.view.View; 14 | import android.view.ViewGroup; 15 | import android.view.Window; 16 | import android.view.WindowManager; 17 | import android.widget.TextView; 18 | 19 | import com.nostra13.universalimageloader.cache.disc.naming.HashCodeFileNameGenerator; 20 | import com.nostra13.universalimageloader.cache.memory.impl.LruMemoryCache; 21 | import com.nostra13.universalimageloader.core.DisplayImageOptions; 22 | import com.nostra13.universalimageloader.core.ImageLoader; 23 | import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; 24 | import com.nostra13.universalimageloader.core.assist.QueueProcessingType; 25 | import com.nostra13.universalimageloader.core.download.BaseImageDownloader; 26 | 27 | import java.lang.reflect.Field; 28 | import java.util.ArrayList; 29 | import java.util.List; 30 | 31 | 32 | /** 33 | * Created by xmuSistone on 2016/9/18. 34 | */ 35 | public class MainActivity extends FragmentActivity { 36 | 37 | private TextView indicatorTv; 38 | private View positionView; 39 | private ViewPager viewPager; 40 | private List fragments = new ArrayList<>(); // 供ViewPager使用 41 | private final String[] imageArray = {"assets://image1.jpg", "assets://image2.jpg", "assets://image3.jpg", "assets://image4.jpg", "assets://image5.jpg"}; 42 | 43 | @Override 44 | protected void onCreate(Bundle savedInstanceState) { 45 | super.onCreate(savedInstanceState); 46 | setContentView(R.layout.activity_main); 47 | 48 | // 1. 沉浸式状态栏 49 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 50 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 51 | getWindow().setStatusBarColor(Color.TRANSPARENT); 52 | getWindow() 53 | .getDecorView() 54 | .setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); 55 | } else { 56 | getWindow() 57 | .setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 58 | } 59 | } 60 | positionView = findViewById(R.id.position_view); 61 | dealStatusBar(); // 调整状态栏高度 62 | 63 | // 2. 初始化ImageLoader 64 | initImageLoader(); 65 | 66 | // 3. 填充ViewPager 67 | fillViewPager(); 68 | } 69 | 70 | /** 71 | * 填充ViewPager 72 | */ 73 | private void fillViewPager() { 74 | indicatorTv = (TextView) findViewById(R.id.indicator_tv); 75 | viewPager = (ViewPager) findViewById(R.id.viewpager); 76 | 77 | // 1. viewPager添加parallax效果,使用PageTransformer就足够了 78 | viewPager.setPageTransformer(false, new CustPagerTransformer(this)); 79 | 80 | // 2. viewPager添加adapter 81 | for (int i = 0; i < 10; i++) { 82 | // 预先准备10个fragment 83 | fragments.add(new CommonFragment()); 84 | } 85 | 86 | viewPager.setAdapter(new FragmentStatePagerAdapter(getSupportFragmentManager()) { 87 | @Override 88 | public Fragment getItem(int position) { 89 | CommonFragment fragment = fragments.get(position % 10); 90 | fragment.bindData(imageArray[position % imageArray.length]); 91 | return fragment; 92 | } 93 | 94 | @Override 95 | public int getCount() { 96 | return 666; 97 | } 98 | }); 99 | 100 | 101 | // 3. viewPager滑动时,调整指示器 102 | viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { 103 | @Override 104 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 105 | } 106 | 107 | @Override 108 | public void onPageSelected(int position) { 109 | updateIndicatorTv(); 110 | } 111 | 112 | @Override 113 | public void onPageScrollStateChanged(int state) { 114 | 115 | } 116 | }); 117 | 118 | updateIndicatorTv(); 119 | } 120 | 121 | /** 122 | * 更新指示器 123 | */ 124 | private void updateIndicatorTv() { 125 | int totalNum = viewPager.getAdapter().getCount(); 126 | int currentItem = viewPager.getCurrentItem() + 1; 127 | indicatorTv.setText(Html.fromHtml("" + currentItem + " / " + totalNum)); 128 | } 129 | 130 | /** 131 | * 调整沉浸式菜单的title 132 | */ 133 | private void dealStatusBar() { 134 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 135 | int statusBarHeight = getStatusBarHeight(); 136 | ViewGroup.LayoutParams lp = positionView.getLayoutParams(); 137 | lp.height = statusBarHeight; 138 | positionView.setLayoutParams(lp); 139 | } 140 | } 141 | 142 | private int getStatusBarHeight() { 143 | Class c = null; 144 | Object obj = null; 145 | Field field = null; 146 | int x = 0, statusBarHeight = 0; 147 | try { 148 | c = Class.forName("com.android.internal.R$dimen"); 149 | obj = c.newInstance(); 150 | field = c.getField("status_bar_height"); 151 | x = Integer.parseInt(field.get(obj).toString()); 152 | statusBarHeight = getResources().getDimensionPixelSize(x); 153 | } catch (Exception e1) { 154 | e1.printStackTrace(); 155 | } 156 | return statusBarHeight; 157 | } 158 | 159 | @SuppressWarnings("deprecation") 160 | private void initImageLoader() { 161 | ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder( 162 | this) 163 | .memoryCacheExtraOptions(480, 800) 164 | // default = device screen dimensions 165 | .threadPoolSize(3) 166 | // default 167 | .threadPriority(Thread.NORM_PRIORITY - 1) 168 | // default 169 | .tasksProcessingOrder(QueueProcessingType.FIFO) 170 | // default 171 | .denyCacheImageMultipleSizesInMemory() 172 | .memoryCache(new LruMemoryCache(2 * 1024 * 1024)) 173 | .memoryCacheSize(2 * 1024 * 1024).memoryCacheSizePercentage(13) // default 174 | .discCacheSize(50 * 1024 * 1024) // 缓冲大小 175 | .discCacheFileCount(100) // 缓冲文件数目 176 | .discCacheFileNameGenerator(new HashCodeFileNameGenerator()) // default 177 | .imageDownloader(new BaseImageDownloader(this)) // default 178 | .defaultDisplayImageOptions(DisplayImageOptions.createSimple()) // default 179 | .writeDebugLogs().build(); 180 | 181 | // 2.单例ImageLoader类的初始化 182 | ImageLoader imageLoader = ImageLoader.getInstance(); 183 | imageLoader.init(config); 184 | } 185 | 186 | } 187 | -------------------------------------------------------------------------------- /android-page-transition/app/src/main/res/drawable-xxhdpi/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmuSistone/ViewpagerTransition/fa92d8296dbf22e4daef0fd2de7b35a587625ed9/android-page-transition/app/src/main/res/drawable-xxhdpi/background.jpg -------------------------------------------------------------------------------- /android-page-transition/app/src/main/res/drawable-xxhdpi/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmuSistone/ViewpagerTransition/fa92d8296dbf22e4daef0fd2de7b35a587625ed9/android-page-transition/app/src/main/res/drawable-xxhdpi/close.png -------------------------------------------------------------------------------- /android-page-transition/app/src/main/res/drawable-xxhdpi/gps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmuSistone/ViewpagerTransition/fa92d8296dbf22e4daef0fd2de7b35a587625ed9/android-page-transition/app/src/main/res/drawable-xxhdpi/gps.png -------------------------------------------------------------------------------- /android-page-transition/app/src/main/res/drawable-xxhdpi/head1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmuSistone/ViewpagerTransition/fa92d8296dbf22e4daef0fd2de7b35a587625ed9/android-page-transition/app/src/main/res/drawable-xxhdpi/head1.png -------------------------------------------------------------------------------- /android-page-transition/app/src/main/res/drawable-xxhdpi/head2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmuSistone/ViewpagerTransition/fa92d8296dbf22e4daef0fd2de7b35a587625ed9/android-page-transition/app/src/main/res/drawable-xxhdpi/head2.png -------------------------------------------------------------------------------- /android-page-transition/app/src/main/res/drawable-xxhdpi/head3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmuSistone/ViewpagerTransition/fa92d8296dbf22e4daef0fd2de7b35a587625ed9/android-page-transition/app/src/main/res/drawable-xxhdpi/head3.png -------------------------------------------------------------------------------- /android-page-transition/app/src/main/res/drawable-xxhdpi/head4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmuSistone/ViewpagerTransition/fa92d8296dbf22e4daef0fd2de7b35a587625ed9/android-page-transition/app/src/main/res/drawable-xxhdpi/head4.png -------------------------------------------------------------------------------- /android-page-transition/app/src/main/res/drawable-xxhdpi/icon1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmuSistone/ViewpagerTransition/fa92d8296dbf22e4daef0fd2de7b35a587625ed9/android-page-transition/app/src/main/res/drawable-xxhdpi/icon1.png -------------------------------------------------------------------------------- /android-page-transition/app/src/main/res/drawable-xxhdpi/icon2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmuSistone/ViewpagerTransition/fa92d8296dbf22e4daef0fd2de7b35a587625ed9/android-page-transition/app/src/main/res/drawable-xxhdpi/icon2.png -------------------------------------------------------------------------------- /android-page-transition/app/src/main/res/drawable-xxhdpi/icon3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmuSistone/ViewpagerTransition/fa92d8296dbf22e4daef0fd2de7b35a587625ed9/android-page-transition/app/src/main/res/drawable-xxhdpi/icon3.png -------------------------------------------------------------------------------- /android-page-transition/app/src/main/res/drawable-xxhdpi/like.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmuSistone/ViewpagerTransition/fa92d8296dbf22e4daef0fd2de7b35a587625ed9/android-page-transition/app/src/main/res/drawable-xxhdpi/like.png -------------------------------------------------------------------------------- /android-page-transition/app/src/main/res/drawable-xxhdpi/paper_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmuSistone/ViewpagerTransition/fa92d8296dbf22e4daef0fd2de7b35a587625ed9/android-page-transition/app/src/main/res/drawable-xxhdpi/paper_background.png -------------------------------------------------------------------------------- /android-page-transition/app/src/main/res/drawable-xxhdpi/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmuSistone/ViewpagerTransition/fa92d8296dbf22e4daef0fd2de7b35a587625ed9/android-page-transition/app/src/main/res/drawable-xxhdpi/search.png -------------------------------------------------------------------------------- /android-page-transition/app/src/main/res/drawable-xxhdpi/three_dot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmuSistone/ViewpagerTransition/fa92d8296dbf22e4daef0fd2de7b35a587625ed9/android-page-transition/app/src/main/res/drawable-xxhdpi/three_dot.png -------------------------------------------------------------------------------- /android-page-transition/app/src/main/res/drawable-xxhdpi/white_back.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmuSistone/ViewpagerTransition/fa92d8296dbf22e4daef0fd2de7b35a587625ed9/android-page-transition/app/src/main/res/drawable-xxhdpi/white_back.9.png -------------------------------------------------------------------------------- /android-page-transition/app/src/main/res/layout/activity_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 16 | 17 | 25 | 26 | 34 | 35 | 42 | 43 | 52 | 53 | 54 | 55 | 56 | 57 | 60 | 61 | 65 | 66 | 72 | 73 | 82 | 83 | 91 | 92 | 100 | 101 | 102 | 103 | 104 | 109 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /android-page-transition/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 19 | 20 | 21 | 22 | 23 | 24 | 29 | 30 | 36 | 37 | 43 | 44 | 51 | 52 | 53 | 54 | 55 | 56 | 66 | 67 | 68 | 73 | 74 | 75 | 76 | 80 | 81 | 85 | 86 | 92 | 93 | 99 | 100 | 107 | 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /android-page-transition/app/src/main/res/layout/detail_list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | 22 | 23 | 32 | 33 | 42 | 43 | 49 | 50 | 51 | 52 | 60 | 61 | 62 | 67 | 68 | -------------------------------------------------------------------------------- /android-page-transition/app/src/main/res/layout/fragment_common.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 15 | 16 | 17 | 18 | 24 | 25 | 31 | 32 | 43 | 44 | 52 | 53 | 61 | 62 | 69 | 70 | 71 | 72 | 77 | 78 | 86 | 87 | 92 | 93 | 99 | 100 | 106 | 107 | 113 | 114 | 118 | 119 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 142 | 143 | 148 | 149 | 154 | 155 | 163 | 164 | 171 | 172 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | -------------------------------------------------------------------------------- /android-page-transition/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmuSistone/ViewpagerTransition/fa92d8296dbf22e4daef0fd2de7b35a587625ed9/android-page-transition/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android-page-transition/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmuSistone/ViewpagerTransition/fa92d8296dbf22e4daef0fd2de7b35a587625ed9/android-page-transition/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android-page-transition/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmuSistone/ViewpagerTransition/fa92d8296dbf22e4daef0fd2de7b35a587625ed9/android-page-transition/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android-page-transition/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmuSistone/ViewpagerTransition/fa92d8296dbf22e4daef0fd2de7b35a587625ed9/android-page-transition/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android-page-transition/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmuSistone/ViewpagerTransition/fa92d8296dbf22e4daef0fd2de7b35a587625ed9/android-page-transition/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android-page-transition/app/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /android-page-transition/app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /android-page-transition/app/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /android-page-transition/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /android-page-transition/app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 150dp 6 | 20dp 7 | 8 | -------------------------------------------------------------------------------- /android-page-transition/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | pageTransition 3 | 4 | -------------------------------------------------------------------------------- /android-page-transition/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /android-page-transition/app/src/test/java/com/stone/transition/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.stone.transition; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /android-page-transition/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.1.0' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | -------------------------------------------------------------------------------- /android-page-transition/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /android-page-transition/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmuSistone/ViewpagerTransition/fa92d8296dbf22e4daef0fd2de7b35a587625ed9/android-page-transition/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android-page-transition/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Dec 28 10:00:20 PST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip 7 | -------------------------------------------------------------------------------- /android-page-transition/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /android-page-transition/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /android-page-transition/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /capture1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmuSistone/ViewpagerTransition/fa92d8296dbf22e4daef0fd2de7b35a587625ed9/capture1.jpg -------------------------------------------------------------------------------- /gif1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmuSistone/ViewpagerTransition/fa92d8296dbf22e4daef0fd2de7b35a587625ed9/gif1.gif -------------------------------------------------------------------------------- /gif2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmuSistone/ViewpagerTransition/fa92d8296dbf22e4daef0fd2de7b35a587625ed9/gif2.gif -------------------------------------------------------------------------------- /gif3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmuSistone/ViewpagerTransition/fa92d8296dbf22e4daef0fd2de7b35a587625ed9/gif3.gif -------------------------------------------------------------------------------- /pageTransition.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmuSistone/ViewpagerTransition/fa92d8296dbf22e4daef0fd2de7b35a587625ed9/pageTransition.apk --------------------------------------------------------------------------------