├── README.md
├── app
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── listen
│ │ └── test_mogu_view
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── listen
│ │ │ └── test_mogu_view
│ │ │ ├── MainActivity.java
│ │ │ └── viewpager
│ │ │ ├── MoguViewPager.java
│ │ │ ├── MoguViewPagerAdapter.java
│ │ │ ├── MoguViewPagerTag1.java
│ │ │ ├── TransforView.java
│ │ │ ├── TransforViewTag1.java
│ │ │ ├── TransforViewTag2.java
│ │ │ └── ViewModel.java
│ └── res
│ │ ├── drawable-xhdpi
│ │ ├── four_bg.png
│ │ ├── four_bottom_1.png
│ │ ├── four_bottom_2.png
│ │ ├── four_bottom_3.png
│ │ ├── four_top.png
│ │ ├── one_bottom.png
│ │ ├── one_bottom_bg.png
│ │ ├── one_top.png
│ │ ├── three_1.png
│ │ ├── three_2.png
│ │ ├── three_3.png
│ │ ├── three_4.png
│ │ ├── three_5.png
│ │ ├── three_6.png
│ │ ├── two_1.png
│ │ ├── two_2.png
│ │ ├── two_3.png
│ │ ├── two_bg.png
│ │ ├── two_bottom.png
│ │ └── two_top.png
│ │ ├── drawable
│ │ └── select_btn.xml
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ ├── guide_view_four.xml
│ │ ├── guide_view_one.xml
│ │ ├── guide_view_three.xml
│ │ ├── guide_view_two.xml
│ │ └── layout_mogu_viewpager.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-w820dp
│ │ └── dimens.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── listen
│ └── test_mogu_view
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
└── settings.gradle
/README.md:
--------------------------------------------------------------------------------
1 |
2 | README -> [高仿蘑菇街欢迎页](https://www.jianshu.com/p/9dd4027c2107)
3 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 24
5 | buildToolsVersion "25.0.0"
6 | defaultConfig {
7 | applicationId "com.listen.test_mogu_view"
8 | minSdkVersion 16
9 | targetSdkVersion 24
10 | versionCode 1
11 | versionName "1.0"
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
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 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
25 | exclude group: 'com.android.support', module: 'support-annotations'
26 | })
27 | compile 'com.android.support:appcompat-v7:24.2.1'
28 | testCompile 'junit:junit:4.12'
29 | }
30 |
--------------------------------------------------------------------------------
/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 /Users/lisong/Library/Android/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/listen/test_mogu_view/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.listen.test_mogu_view;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.listen.test_mogu_view", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/java/com/listen/test_mogu_view/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.listen.test_mogu_view;
2 |
3 | import android.support.v7.app.AppCompatActivity;
4 | import android.os.Bundle;
5 | import android.view.Window;
6 | import android.view.WindowManager;
7 |
8 | public class MainActivity extends AppCompatActivity {
9 |
10 | @Override
11 | protected void onCreate(Bundle savedInstanceState) {
12 | super.onCreate(savedInstanceState);
13 | requestWindowFeature(Window.FEATURE_NO_TITLE);
14 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
15 | setContentView(R.layout.activity_main);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/listen/test_mogu_view/viewpager/MoguViewPager.java:
--------------------------------------------------------------------------------
1 | package com.listen.test_mogu_view.viewpager;
2 |
3 | import android.content.Context;
4 | import android.support.v4.view.ViewPager;
5 | import android.util.AttributeSet;
6 | import android.view.View;
7 | import android.widget.RelativeLayout;
8 |
9 | import com.listen.test_mogu_view.R;
10 |
11 | import java.util.ArrayList;
12 | import java.util.List;
13 |
14 |
15 | public class MoguViewPager extends RelativeLayout {
16 |
17 | private MoguViewPagerAdapter mAdapter;
18 | private ViewPager mViewPager;
19 | private TransforView mTransforView;
20 | private List mViewList = new ArrayList<>();
21 | private int[] mLayouts = new int[] {R.layout.guide_view_one, R.layout.guide_view_two, R.layout.guide_view_three,
22 | R.layout.guide_view_four};
23 |
24 | public MoguViewPager(Context context) {
25 | super(context);
26 | init();
27 | }
28 |
29 | public MoguViewPager(Context context, AttributeSet attrs) {
30 | super(context, attrs);
31 | init();
32 | }
33 |
34 | private void init() {
35 | inflate(getContext(), R.layout.layout_mogu_viewpager, this);
36 |
37 | mViewPager = (ViewPager) this.findViewById(R.id.viewpager);
38 | mTransforView = (TransforView) this.findViewById(R.id.transfor_view);
39 |
40 | {
41 | /** 初始化4个页面 */
42 | for (int i = 0; i < mLayouts.length; i++) {
43 | View view = View.inflate(getContext(), mLayouts[i], null);
44 | mViewList.add(view);
45 | }
46 | }
47 |
48 | mAdapter = new MoguViewPagerAdapter(mViewList, getContext());
49 | mViewPager.setAdapter(mAdapter);
50 | mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
51 | @Override
52 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
53 | mTransforView.transfor(position, positionOffset, positionOffsetPixels);
54 | }
55 |
56 | @Override
57 | public void onPageSelected(int position) {
58 |
59 | }
60 |
61 | @Override
62 | public void onPageScrollStateChanged(int state) {
63 |
64 | }
65 | });
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/app/src/main/java/com/listen/test_mogu_view/viewpager/MoguViewPagerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.listen.test_mogu_view.viewpager;
2 |
3 | import android.content.Context;
4 | import android.support.v4.view.PagerAdapter;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 |
8 | import java.util.List;
9 |
10 | public class MoguViewPagerAdapter extends PagerAdapter {
11 |
12 | private List mViewList;
13 | private Context mContext;
14 |
15 | public MoguViewPagerAdapter(List mImageViewList, Context context) {
16 | mViewList = mImageViewList;
17 | mContext = context;
18 | }
19 |
20 | @Override
21 | public void destroyItem(ViewGroup container, int position, Object object) {
22 | container.removeView(mViewList.get(position));
23 | }
24 |
25 | @Override
26 | public Object instantiateItem(ViewGroup container, int position) {
27 | View view = mViewList.get(position);
28 | container.addView(view);
29 | return view;
30 | }
31 |
32 | @Override
33 | public int getCount() {
34 | return mViewList == null ? 0 : mViewList.size();
35 | }
36 |
37 | @Override
38 | public boolean isViewFromObject(View view, Object object) {
39 | return view == object;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/app/src/main/java/com/listen/test_mogu_view/viewpager/MoguViewPagerTag1.java:
--------------------------------------------------------------------------------
1 | package com.listen.test_mogu_view.viewpager;
2 |
3 | import android.content.Context;
4 | import android.support.v4.view.ViewPager;
5 | import android.util.AttributeSet;
6 | import android.view.View;
7 | import android.widget.RelativeLayout;
8 |
9 | import com.listen.test_mogu_view.R;
10 |
11 | import java.util.ArrayList;
12 | import java.util.List;
13 |
14 |
15 | public class MoguViewPagerTag1 extends RelativeLayout {
16 |
17 | private MoguViewPagerAdapter mAdapter;
18 | private ViewPager mViewPager;
19 | private List mViewList = new ArrayList<>();
20 | private int[] mLayouts = new int[] {R.layout.guide_view_one, R.layout.guide_view_two, R.layout.guide_view_three,
21 | R.layout.guide_view_four};
22 |
23 | public MoguViewPagerTag1(Context context) {
24 | super(context);
25 | init();
26 | }
27 |
28 | public MoguViewPagerTag1(Context context, AttributeSet attrs) {
29 | super(context, attrs);
30 | init();
31 | }
32 |
33 | private void init() {
34 | inflate(getContext(), R.layout.layout_mogu_viewpager, this);
35 | mViewPager = (ViewPager) this.findViewById(R.id.viewpager);
36 | {
37 | /** 初始化4个页面 */
38 | for (int i = 0; i < mLayouts.length; i++) {
39 | View view = View.inflate(getContext(), mLayouts[i], null);
40 | mViewList.add(view);
41 | }
42 | }
43 |
44 | mAdapter = new MoguViewPagerAdapter(mViewList, getContext());
45 | mViewPager.setAdapter(mAdapter);
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/app/src/main/java/com/listen/test_mogu_view/viewpager/TransforView.java:
--------------------------------------------------------------------------------
1 | package com.listen.test_mogu_view.viewpager;
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.RectF;
8 | import android.support.annotation.NonNull;
9 | import android.util.AttributeSet;
10 | import android.util.Log;
11 | import android.view.View;
12 |
13 | import com.listen.test_mogu_view.R;
14 |
15 |
16 | public class TransforView extends View {
17 |
18 | // /////////////////////////////////////////////////////////////////////////
19 | // 页面切换时的,白色矩形背景的变化参数
20 | // /////////////////////////////////////////////////////////////////////////
21 | /**
22 | * 第1页->第2页
23 | */
24 | public static final float FIRST_HEIGHT = 0.4f;// 第1个页面高度缩放比例,正:放大,负:缩小
25 | public final int FIRST_TOP1 = -dp2px(30);// 第1个页面top移动距离,正:下移,负:上移
26 | public final int FIRST_TOP2 = dp2px(60);// 第1个页面top移动距离,正:下移,负:上移
27 | public static final float FIRST_RATE = 0.5f;// 在偏移50%处,进行下一页的显示
28 | /**
29 | * 第2页->第3页
30 | */
31 | public static final float SECOND_WIDTH = -0.15f;// 第2个页面宽度缩放比例,正:放大,负:缩小
32 | public final int SECOND_TOP = -dp2px(20);// 第2个页面top移动距离比例,正:下移,负:上移
33 | public static final float SECOND_RATE = 0.5f;// 在偏移50%处,进行下一页的显示
34 | /**
35 | * 第3页->第4页
36 | */
37 | public static final float THIRD_WIDTH = -0.1f;// 第3个页面宽度缩放比例,正:放大,负:缩小
38 | public static final float THIRD_HEIGHT = -0.1f;// 第3个页面高度缩放比例,正:放大,负:缩小
39 | public static final int THIRD_DEGREE = -10;// 第3个页面角度调整,正:顺时针,负:逆时针
40 | public static final float THIRD_RATE = 0.5f;// 在偏移50%处,进行下一页的显示
41 |
42 | // /////////////////////////////////////////////////////////////////////////
43 | // 白色圆角矩形背景
44 | // /////////////////////////////////////////////////////////////////////////
45 | private Paint mRectBgPaint;
46 | private int mRectBgDefaultCorner = dp2px(5);// 初始圆角5dp
47 | private float mRectBgCurrentDegree = 0;// 默认不旋转
48 |
49 | /**
50 | * 第1页初始化
51 | * default=默认初始宽高,left,top,如果是2,3,4页,则表示变化后的值
52 | * current=当前宽高,left,top,会根据偏移量变化
53 | */
54 | private float mPage1RectBgDefaultWidth = dp2px(260);
55 | private float mPage1RectBgDefaultHeight = dp2px(230);
56 | private float mPage1RectBgDefaultLeft = getScreenWidth() / 2 - mPage1RectBgDefaultWidth / 2;
57 | private float mPage1RectBgDefaultTop = dp2px(80);
58 |
59 | private float mRectBgCurrentWidth = mPage1RectBgDefaultWidth;
60 | private float mRectBgCurrentHeight = mPage1RectBgDefaultHeight;
61 | private float mRectBgCurrentLeft = mPage1RectBgDefaultLeft;
62 | private float mRectBgCurrentTop = mPage1RectBgDefaultTop;
63 |
64 | /**
65 | * 第1页->第2页
66 | * 在第1页的基础上进行变化
67 | * 1.height放大
68 | * 2.top先上移n,在下移n*2
69 | */
70 | private float mPage2RectBgDefaultWidth = mPage1RectBgDefaultWidth;
71 | private float mPage2RectBgDefaultHeight = mPage1RectBgDefaultHeight * (1 + FIRST_HEIGHT);
72 | private float mPage2RectBgDefaultLeft = mPage1RectBgDefaultLeft;
73 | private float mPage2RectBgDefaultTop = mPage1RectBgDefaultTop + FIRST_TOP1 + FIRST_TOP2;
74 |
75 | /**
76 | * 第2页->第3页
77 | * 在第2页的基础上进行变化
78 | * 1.宽度缩小
79 | * 2.top上移
80 | */
81 | private float mPage3RectBgDefaultWidth = mPage2RectBgDefaultWidth * (1 + SECOND_WIDTH);
82 | private float mPage3RectBgDefaultHeight = mPage2RectBgDefaultHeight;
83 | private float mPage3RectBgDefaultLeft = getScreenWidth() / 2 - mPage3RectBgDefaultWidth / 2;
84 | private float mPage3RectBgDefaultTop = mPage2RectBgDefaultTop + SECOND_TOP;
85 |
86 | /**
87 | * 第3页->第4页
88 | * 在第3页的基础上进行变化
89 | * 1.宽度缩小
90 | * 2.高度缩小
91 | * 2.逆时针旋转
92 | */
93 | private float mPage4RectBgDefaultWidth = mPage3RectBgDefaultWidth * (1 + THIRD_WIDTH);
94 | private float mPage4RectBgDefaultHeight = mPage3RectBgDefaultHeight * (1 + THIRD_HEIGHT);
95 | private float mPage4RectBgDefaultLeft = getScreenWidth() / 2 - mPage4RectBgDefaultWidth / 2;
96 | private float mPage4RectBgDefaultTop = mPage3RectBgDefaultTop;
97 | private float mPage4ModelDefaultWidth = (mPage4RectBgDefaultWidth - padding() * 4) / 3;
98 |
99 | // /////////////////////////////////////////////////////////////////////////
100 | // 第1页,view元素
101 | // /////////////////////////////////////////////////////////////////////////
102 | private ViewModel mPage1Top;// 顶部模特图
103 | private ViewModel mPage1Bottom;// 底部文案图
104 | private ViewModel mPage1BottomBg;// 底部背景图
105 |
106 | // /////////////////////////////////////////////////////////////////////////
107 | // 第2页,view元素
108 | // /////////////////////////////////////////////////////////////////////////
109 | private int[] mPage2ModelResources = new int[] {R.drawable.two_1, R.drawable.two_2, R.drawable.two_3};
110 | private ViewModel mPage2Top;// 顶部文案图
111 | private ViewModel[] mPage2Center = new ViewModel[mPage2ModelResources.length];// 中间3张模特图
112 | private ViewModel mPage2Bottom;// 底部文案图
113 | private ViewModel[] mPage2Split = new ViewModel[2];// 2张裂变背景图
114 |
115 | // /////////////////////////////////////////////////////////////////////////
116 | // 第3页,view元素
117 | // /////////////////////////////////////////////////////////////////////////
118 | private int[] mPage3ModelResources = new int[] {R.drawable.three_1, R.drawable.three_2, R.drawable.three_3,
119 | R.drawable.three_4, R.drawable.three_5, R.drawable.three_6};
120 | private ViewModel[] mPage3Model = new ViewModel[mPage3ModelResources.length];// 6张模特图
121 | private float mPage3ModelDefaultWidth = (mPage3RectBgDefaultWidth - padding() * 4) / 3;// 每张模特图的默认宽度
122 | private float mPage3ModelDefaultHeight = (mPage3RectBgDefaultHeight - padding() * 3) / 2;// 每张模特图的默认高度
123 |
124 | // /////////////////////////////////////////////////////////////////////////
125 | // 第4页,view元素
126 | // /////////////////////////////////////////////////////////////////////////
127 | private int[] mPage4ModelResources = new int[] {R.drawable.four_bottom_1, R.drawable.four_bottom_2,
128 | R.drawable.four_bottom_3};
129 | private ViewModel mPage4Top;// 顶部模特图
130 | private ViewModel[] mPage4Model = new ViewModel[mPage4ModelResources.length];// 底部3张模特图
131 | private ViewModel[] mPage4Split = new ViewModel[2];// 2张裂变背景图
132 | // private float mPage4SplitTargeOffset =
133 |
134 | /**
135 | * 当前页数索引
136 | */
137 | private int mCurrentPageIndex;
138 |
139 | public TransforView(Context context) {
140 | super(context);
141 | init();
142 | }
143 |
144 | public TransforView(Context context, AttributeSet attrs) {
145 | super(context, attrs);
146 | init();
147 | }
148 |
149 | public TransforView(Context context, AttributeSet attrs, int defStyle) {
150 | super(context, attrs, defStyle);
151 | init();
152 | }
153 |
154 | public void transfor(int position, float positionOffset, int positionOffsetPixels) {
155 | Log.e("ls_debug_log", "p=" + position + ",p_offset=" + positionOffset + ",p_px=" + positionOffsetPixels);
156 | mCurrentPageIndex = position;
157 | calculateOffset(position, positionOffset, positionOffsetPixels);
158 | }
159 |
160 | private void init() {
161 | {
162 | /** 第1页,初始化矩形背景 */
163 | mRectBgPaint = new Paint();
164 | mRectBgPaint.setAntiAlias(true); // 设置画笔为无锯齿
165 | mRectBgPaint.setColor(Color.BLACK); // 设置画笔颜色
166 | mRectBgPaint.setStyle(Paint.Style.FILL); // 空心效果
167 | }
168 | {
169 | /** 第1页,顶部模特图 */
170 | mPage1Top = new ViewModel(getContext(), R.drawable.one_top).alpha(255)
171 | // 宽度为矩形背景宽度,减去左,右,各5dp边距
172 | .width(mPage1RectBgDefaultWidth - padding() * 2)
173 | // 高度为矩形背景的高度,减去上,中,下各5边距后剩余的高度的2/3
174 | .height((mPage1RectBgDefaultHeight - padding() * 3) / 3 * 2)
175 | .left(mPage1RectBgDefaultLeft + padding())
176 | .top(mPage1RectBgDefaultTop + padding())
177 | .create();
178 |
179 | /** 第1页,底部文案图 */
180 | mPage1Bottom = new ViewModel(getContext(), R.drawable.one_bottom).alpha(255)
181 | // 宽度为矩形背景宽度,减去左,右,各5dp边距
182 | .width(mPage1RectBgDefaultWidth - padding() * 2)
183 | // 高度为矩形背景的高度,减去上,中,下各5dp边距后剩余的高度的1/3
184 | .height((mPage1RectBgDefaultHeight - padding() * 3) / 3)
185 | .left(mPage1RectBgDefaultLeft + padding())
186 | // top距离=顶部模特图top+height+5dp边距
187 | .top(mPage1Top.defaultTop + mPage1Top.defaultHeight + padding())
188 | .create();
189 |
190 | /** 第1页,底部背景图 */
191 | mPage1BottomBg =
192 | new ViewModel(getContext(), R.drawable.one_bottom_bg).alpha(255)
193 | .width(mPage1RectBgDefaultWidth - padding() * 2)
194 | // .height()// 不传则按宽度比例缩放
195 | .left(mPage1RectBgDefaultLeft + padding())
196 | // top距离=矩形背景top+height+5dp边距
197 | .top(mPage1RectBgDefaultTop + mPage1RectBgDefaultHeight + padding())
198 | .create();
199 | }
200 |
201 | {
202 |
203 | /** 第2页,顶部文案图 */
204 | mPage2Top = new ViewModel(getContext(), R.drawable.two_top).width(mPage2RectBgDefaultWidth - padding() * 2)
205 | // .height()// 不传则按宽度比例缩放
206 | .left(mPage2RectBgDefaultLeft + padding())
207 | .top(mPage2RectBgDefaultTop + padding())
208 | .create();
209 |
210 | /** 第2页,中间3张模特图 */
211 | for (int i = 0; i < mPage2ModelResources.length; i++) {
212 | mPage2Center[i] = new ViewModel(getContext(), mPage2ModelResources[i]);
213 | if (i == 0) {
214 | /** 第1张模特图 */
215 | mPage2Center[i].width((mPage2RectBgDefaultWidth - dp2px(15)) / 3 * 2)
216 | .height(mPage2Center[i].defaultWidth + dp2px(5))
217 | .left(mPage2RectBgDefaultLeft + padding())
218 | .top(mPage2Top.defaultTop + mPage2Top.defaultHeight + padding())
219 | .create();
220 | } else if (i == 1) {
221 | /** 第2张模特图 */
222 | mPage2Center[i].width((mPage2RectBgDefaultWidth - dp2px(15)) / 3)
223 | .height(mPage2Center[i].defaultWidth)
224 | .left(mPage2Center[0].defaultLeft + mPage2Center[0].defaultWidth + padding())
225 | .top(mPage2Top.defaultTop + mPage2Top.defaultHeight + padding())
226 | .create();
227 | } else if (i == 2) {
228 | /** 第3张模特图 */
229 | mPage2Center[i].width((mPage2RectBgDefaultWidth - dp2px(15)) / 3)
230 | .height(mPage2Center[i].defaultWidth)
231 | .left(mPage2Center[0].defaultLeft + mPage2Center[0].defaultWidth + padding())
232 | .top(mPage2Center[1].defaultTop + mPage2Center[1].defaultHeight + padding())
233 | .create();
234 | }
235 | }
236 |
237 | /** 第2页,底部文案图 */
238 | mPage2Bottom =
239 | new ViewModel(getContext(), R.drawable.two_bottom).width(mPage2RectBgDefaultWidth - padding() * 2)
240 | .height(
241 | mPage2RectBgDefaultHeight - mPage2Top.defaultHeight - mPage2Center[0].defaultHeight - padding()
242 | * 4)
243 | .left(mPage2RectBgDefaultLeft + padding())
244 | .top(mPage2Center[0].defaultTop + mPage2Center[0].defaultHeight + padding())
245 | .create();
246 |
247 | /** 第2页,裂变背景图 */
248 | for (int i = 0; i < 2; i++) {
249 | mPage2Split[i] =
250 | new ViewModel(getContext(), R.drawable.two_bg).width(mPage2RectBgDefaultWidth)
251 | .height(mPage2RectBgDefaultHeight)
252 | .left(mPage2RectBgDefaultLeft)
253 | .top(mPage2RectBgDefaultTop)
254 | .create();
255 |
256 | }
257 | }
258 |
259 | {
260 | /** 第3页,6张模特图 */
261 | for (int i = 0; i < mPage3Model.length; i++) {
262 | if (i < mPage3Model.length / 2) {
263 | /** 第3页,第1排3张模特图 */
264 | mPage3Model[i] =
265 | new ViewModel(getContext(), mPage3ModelResources[i]).width(mPage3ModelDefaultWidth)
266 | .height(mPage3ModelDefaultHeight)
267 | .left(mPage3RectBgDefaultLeft + mPage3ModelDefaultWidth * i + padding() * (i + 1))
268 | .top(mPage3RectBgDefaultTop + padding())
269 | .create();
270 | } else {
271 | /** 第3页,第2排3张模特图 */
272 | mPage3Model[i] =
273 | new ViewModel(getContext(), mPage3ModelResources[i]).width(mPage3ModelDefaultWidth)
274 | .height(mPage3ModelDefaultHeight)
275 | .left(
276 | mPage3RectBgDefaultLeft + mPage3ModelDefaultWidth * (i - mPage3Model.length / 2)
277 | + padding() * ((i - mPage3Model.length / 2) + 1))
278 | // 与第1排第区别在于top需要加上第1排的height
279 | .top(mPage3RectBgDefaultTop + mPage3Model[i - 1].defaultHeight + padding() * 2)
280 | .create();
281 | }
282 | mPage3Model[i].paint.setAntiAlias(true);
283 |
284 | }
285 | }
286 |
287 | {
288 | /** 第4页,顶部模特图 */
289 | mPage4Top =
290 | new ViewModel(getContext(), R.drawable.four_top).width(mPage4RectBgDefaultWidth - padding() * 2)
291 | .left(mPage4RectBgDefaultLeft + padding())
292 | .top(mPage4RectBgDefaultTop + padding())
293 | .create();
294 | mPage4Top.paint.setAntiAlias(true);
295 |
296 | /** 第4页,底部3张模特图 */
297 | for (int i = 0; i < mPage4ModelResources.length; i++) {
298 | mPage4Model[i] =
299 | new ViewModel(getContext(), mPage4ModelResources[i]).width(mPage4ModelDefaultWidth)
300 | .height(mPage4RectBgDefaultHeight - padding() * 3 - mPage4Top.defaultHeight)
301 | .left(mPage4RectBgDefaultLeft + mPage4ModelDefaultWidth * i + padding() * (i + 1))
302 | .top(mPage4Top.defaultTop + mPage4Top.defaultHeight + padding());
303 | mPage4Model[i].paint.setAntiAlias(true);
304 | }
305 |
306 | /** 第4页,2张裂变背景图 */
307 | for (int i = 0; i < mPage4Split.length; i++) {
308 | mPage4Split[i] = new ViewModel(getContext(), R.drawable.four_bg)
309 | .width(mPage4RectBgDefaultWidth)
310 | .height(mPage4RectBgDefaultHeight)
311 | .left(mPage4RectBgDefaultLeft)
312 | .top(mPage4RectBgDefaultTop);
313 |
314 | }
315 | }
316 | }
317 |
318 | /**
319 | * @desc 根据viewPager偏移,修改view的宽,高,left,top
320 | * @author listen
321 | */
322 | private void calculateOffset(int position, float positionOffset, int positionOffsetPixels) {
323 | if (positionOffset <= 0) {
324 | return;
325 | }
326 | if (fromPage1ToPage2(position)) {
327 | /** 第1页,底部背景图,根据页面向左偏移 */
328 | mPage1BottomBg.currentLeft = mPage1BottomBg.defaultLeft - positionOffsetPixels;
329 |
330 | if (positionOffset < FIRST_RATE) {
331 | /** 快速滑动的时候,可能丢失最后一次绘制,所以需要在这里重新设置一次,保证第2页的view不可见 */
332 | hidePage2Views();
333 |
334 | /** 第1页,在0->50%区间偏移 */
335 | /** 矩形背景,高度放大40%,向上移动30dp */
336 | transformRectBgFrom1To2Before(positionOffset);
337 |
338 | /** 第1页,渐渐隐顶部图,底部图;透明度渐变消失,偏移到50%时完全消失 */
339 | stepByHidePage1Views(positionOffset);
340 |
341 | } else {
342 | /** 快速滑动的时候,可能丢失最后一次绘制,所以需要在这里调重新设置一次。保证第1页的view不可见 */
343 | hidePage1Views();
344 |
345 | /** 第1页,在50%->100%区间偏移 */
346 | /** 矩形背景,上移30dp后,向下偏移60dp */
347 | transformRectBgFrom1To2After(positionOffset);
348 |
349 | /** 第2页,渐渐显示顶部,3张模特图,底部图 */
350 | stepByShowPage2Views(positionOffset);
351 |
352 | }
353 | } else if (fromPage2ToPage3(position)) {
354 | /** 矩形背景,宽度缩小15%,上移20dp */
355 | transformRectBgFrom2To3(positionOffset);
356 |
357 | if (positionOffset < SECOND_RATE) {
358 | /** 快速滑动的时候,可能丢失最后一次绘制,所以需要在这里调重新设置一次。保证第3页滑回到第2页时,第3页的view不可见 */
359 | hidePage3Views();
360 | /** 第2页,在0->50%区间偏移,渐渐隐藏顶部,中间,底部,裂变背景图 */
361 | stepByHidePage2Views(positionOffset, positionOffsetPixels);
362 | } else {
363 | /** 快速滑动的时候,可能丢失最后一次绘制,所以需要在这里调重新设置一次,保证第2页的view不可见 */
364 | hidePage2Views();
365 | /** 第2页,在50->100%区间偏移,渐渐显示第3页,6张模特图 */
366 | stepByShowPage3Views(positionOffset);
367 | }
368 | } else if (fromPage3ToPage4(position)) {
369 |
370 | /** 背景矩形的宽度,高度减少10%,逆时针旋转10度 */
371 | transformRectBgFrom3To4(positionOffset);
372 |
373 | if (positionOffset < THIRD_RATE) {
374 |
375 | /** 快速滑动的时候,可能丢失最后一次绘制,所以需要在这里调重新设置一次,保证第4页的view不可见 */
376 | hidePage4Views();
377 |
378 | /** 渐渐缩放,隐藏第3页,6张模特图 */
379 | stepByHidePage3Views(positionOffset);
380 |
381 | } else {
382 | /** 快速滑动的时候,可能丢失最后一次绘制,所以需要在这里调重新设置一次,保证第3页的view缩放完成 */
383 | scaleHidePage3Views();
384 |
385 | /** 渐渐显示第4页,顶部图,底部3张模特图,分裂背景图 */
386 | stepByShowPage4Views(positionOffset);
387 | }
388 | }
389 | postInvalidate();
390 | }
391 |
392 | private void stepByShowPage4Views(float positionOffset) {
393 | /** 显示第4页,裂变背景图,并向左右平移 */
394 | float offset = (mPage4RectBgDefaultWidth + dp2px(40)) * ((positionOffset - THIRD_RATE) * (1 / (1 - THIRD_RATE)));
395 | for (int i = 0; i < mPage4Split.length; i++) {
396 | mPage4Split[i].matrix.reset();
397 | mPage4Split[i].matrix.postScale(mPage4RectBgDefaultWidth / mPage4Split[i].bitmap.getWidth(), mPage4RectBgDefaultHeight / mPage4Split[i].bitmap.getHeight());
398 |
399 | float currentLeft = 0;
400 | if (i == 0) {
401 | // 左移
402 | currentLeft = mPage4RectBgDefaultLeft - offset;
403 | } else if (i == 1) {
404 | // 右移
405 | currentLeft = mPage4RectBgDefaultLeft + offset;
406 | }
407 |
408 | // 平移
409 | mPage4Split[i].matrix.postTranslate(currentLeft, mPage4RectBgDefaultTop);
410 | // 旋转角度
411 | mPage4Split[i].matrix.postRotate(THIRD_DEGREE, currentLeft + mPage4RectBgDefaultWidth/2,
412 | mPage4RectBgDefaultTop + mPage4RectBgDefaultHeight/2);
413 |
414 | mPage4Split[i].alpha((int) (255 * ((positionOffset - THIRD_RATE) * (1 / (1 - THIRD_RATE)))));
415 | }
416 |
417 | /** 显示第4页,顶部模特图 */
418 | mPage4Top.alpha((int) (255 * ((positionOffset - THIRD_RATE) * (1 / (1 - THIRD_RATE)))));
419 |
420 | /** 显示第4页,底部3张模特图 */
421 | for (int i = 0; i < mPage4Model.length; i++) {
422 | if (i == 0) {
423 | mPage4Model[i].currentWidth =
424 | mPage4Model[i].defaultWidth * ((positionOffset - THIRD_RATE) * (1 / (1 - THIRD_RATE)));
425 | mPage4Model[i].currentHeight =
426 | mPage4Model[i].defaultHeight * ((positionOffset - THIRD_RATE) * (1 / (1 - THIRD_RATE)));
427 | mPage4Model[i].alpha((int) (255 * (positionOffset - THIRD_RATE) * (1 / (1 - THIRD_RATE))));
428 | } else {
429 | if (mPage4Model[i - 1].currentWidth >= mPage4ModelDefaultWidth / 2) {
430 | mPage4Model[i].currentWidth =
431 | mPage4Model[i].defaultWidth * ((mPage4Model[i - 1].widthRate() - 0.5f) * 2);
432 | mPage4Model[i].currentHeight =
433 | mPage4Model[i].defaultHeight * ((mPage4Model[i - 1].widthRate() - 0.5f) * 2);
434 | mPage4Model[i].currentLeft =
435 | mPage4Model[i - 1].currentLeft + mPage4Model[i - 1].currentWidth + padding();
436 | mPage4Model[i].alpha((int) (255 * (mPage4Model[i - 1].widthRate() - 0.5f) * 2));
437 | }
438 | }
439 | }
440 | }
441 |
442 | private void transformRectBgFrom3To4(float positionOffset) {
443 | /** 快速滑动的时候,可能丢失最后一次绘制,所以需要在这里调重新设置一次,保证变化完成 */
444 | mRectBgCurrentWidth = mPage3RectBgDefaultWidth;
445 | mRectBgCurrentTop = mPage3RectBgDefaultTop;
446 |
447 | /** 调整第4页,背景矩形的宽高和角度 */
448 | /** 背景矩形的宽度,在第3页调整宽度的基础上进行缩小 */
449 | mRectBgCurrentWidth = mPage3RectBgDefaultWidth * (1 + THIRD_WIDTH * positionOffset);
450 | mRectBgCurrentLeft = getScreenWidth() / 2 - mRectBgCurrentWidth / 2;
451 | /** 背景矩形的高度,在第2页调整高度的基础上进行缩小 */
452 | mRectBgCurrentHeight = mPage3RectBgDefaultHeight * (1 + THIRD_HEIGHT * positionOffset);
453 | /** 背景矩形逆时针旋转 */
454 | mRectBgCurrentDegree = THIRD_DEGREE * positionOffset;
455 | }
456 |
457 | private void stepByHidePage3Views(float positionOffset) {
458 | /** 隐藏第3页6张模特图 */
459 | /** 从第1排,第3-1张开始,依次缩放 */
460 | for (int i = mPage3ModelResources.length / 2 - 1; i >= 0; i--) {
461 | if (i == mPage3ModelResources.length / 2 - 1) {
462 | /** 如果是第1排,第3张,则开始缩放 */
463 | mPage3Model[i].currentHeight =
464 | mPage3Model[i].defaultHeight * (1 - positionOffset * (1 / (1 - THIRD_RATE)));
465 | mPage3Model[i].currentWidth =
466 | mPage3Model[i].defaultWidth * (1 - positionOffset * (1 / (1 - THIRD_RATE)));
467 | } else {
468 | /** 如果是第1排,第1/2张,则判断后1张缩放到一半的时候开始自己的缩放 */
469 | if (mPage3Model[i + 1].currentHeight <= mPage3Model[i + 1].defaultHeight / 2) {
470 | mPage3Model[i].currentHeight = mPage3Model[i].defaultHeight * mPage3Model[i + 1].heightRate() * 2;
471 | mPage3Model[i].currentWidth = mPage3Model[i].defaultWidth * mPage3Model[i + 1].heightRate() * 2;
472 | } else {
473 | mPage3Model[i].currentHeight = mPage3Model[i].defaultHeight;
474 | mPage3Model[i].currentWidth = mPage3Model[i].defaultWidth;
475 | }
476 | }
477 |
478 | /** 跳转left,top,实现居中缩放 */
479 | mPage3Model[i].currentLeft =
480 | mPage3Model[i].defaultLeft + mPage3Model[i].defaultWidth / 2 - mPage3Model[i].currentWidth / 2;
481 | mPage3Model[i].currentTop =
482 | mPage3Model[i].defaultTop + mPage3Model[i].defaultHeight / 2 - mPage3Model[i].currentHeight / 2;
483 | }
484 |
485 | /** 从第1排,第4-6张开始,依次缩放 */
486 | for (int i = mPage3ModelResources.length / 2; i < mPage3ModelResources.length; i++) {
487 | if (i == mPage3ModelResources.length / 2) {
488 | /** 如果是第2排,第1张,则开始缩放 */
489 | mPage3Model[i].currentHeight =
490 | mPage3Model[i].defaultHeight * (1 - positionOffset * (1 / (1 - THIRD_RATE)));
491 | mPage3Model[i].currentWidth =
492 | mPage3Model[i].defaultWidth * (1 - positionOffset * (1 / (1 - THIRD_RATE)));
493 | } else {
494 | /** 如果是第2排,第5/6张,则判断前1张缩放到一半的时候开始自己的缩放 */
495 | if (mPage3Model[i - 1].currentHeight <= mPage3Model[i - 1].defaultHeight / 2) {
496 | mPage3Model[i].currentHeight = mPage3Model[i].defaultHeight * mPage3Model[i - 1].heightRate() * 2;
497 | mPage3Model[i].currentWidth = mPage3Model[i].defaultWidth * mPage3Model[i - 1].heightRate() * 2;
498 | } else {
499 | mPage3Model[i].currentHeight = mPage3Model[i].defaultHeight;
500 | mPage3Model[i].currentWidth = mPage3Model[i].defaultWidth;
501 | }
502 | }
503 |
504 | /** 跳转left,top,实现居中缩放 */
505 | mPage3Model[i].currentLeft =
506 | mPage3Model[i].defaultLeft + mPage3Model[i].defaultWidth / 2 - mPage3Model[i].currentWidth / 2;
507 | mPage3Model[i].currentTop =
508 | mPage3Model[i].defaultTop + mPage3Model[i].defaultHeight / 2 - mPage3Model[i].currentHeight / 2;
509 | }
510 | }
511 |
512 | private void transformRectBgFrom1To2Before(float positionOffset) {
513 | /** 矩形背景,高度放大40% */
514 | /**
515 | * 偏移到50%的时候height需要放大40%,defaultHeight=400,targetHeight=400*1.4=560
516 | *
517 | * offset=0
518 | * 400 * (1 + 0.4 * 0 * (1 / 0.5)) = 400
519 | *
520 | * offset=0.25
521 | * 400 * (1 + 0.4 * 0.25 * (1 / 0.5)) = 400 * 1.2 = 480
522 | *
523 | * offset=0.5
524 | * 400 * (1 + 0.4 * 0.5 * (1 / 0.5)) = 400 * 1.4 = 560
525 | *
526 | */
527 | mRectBgCurrentHeight =
528 | (int) (mPage1RectBgDefaultHeight * (1 + FIRST_HEIGHT * positionOffset * (1 / FIRST_RATE)));
529 | /** 矩形背景,向上移动30dp */
530 | mRectBgCurrentTop = (int) (mPage1RectBgDefaultTop + (FIRST_TOP1 * positionOffset * (1 / FIRST_RATE)));
531 | }
532 |
533 | private void stepByHidePage1Views(float positionOffset) {
534 | /**
535 | * 偏移到50%的时候alpha需要为0,view不可见
536 | *
537 | * offset=0
538 | * 255-(255*0.0*(1/0.5)) = 0
539 | *
540 | * offset=0.25
541 | * 255-(255*0.25*(1/0.5)) = 127
542 | *
543 | * offset=0.5
544 | * 255-(255*0.5*(1/0.5)) = 255
545 | */
546 | mPage1Top.alpha((int) (255 - (255 * positionOffset * (1 / FIRST_RATE))));
547 | mPage1Bottom.alpha((int) (255 - (255 * positionOffset * (1 / FIRST_RATE))));
548 |
549 | /** 第1页,顶部图向下移动 */
550 | mPage1Top.currentTop = mPage1Top.defaultTop + (FIRST_TOP2 + FIRST_TOP1) * positionOffset * (1 / FIRST_RATE);
551 |
552 | /** 第1页,底部图跟随顶部图向下移动 */
553 | mPage1Bottom.currentTop = mPage1Top.currentTop + mPage1Top.defaultHeight + padding();
554 | }
555 |
556 | private void transformRectBgFrom1To2After(float positionOffset) {
557 | /** 快速滑动的时候,可能丢失最后一次绘制,所以需要在这里调重新设置一次,保证变化完成 */
558 | mRectBgCurrentHeight = mPage2RectBgDefaultHeight;
559 | mRectBgCurrentTop = mPage1RectBgDefaultTop + FIRST_TOP1;
560 | /** 第1页,在50%->100%区间偏移 */
561 | /** 矩形背景,在上上偏移30dp后,向下偏移60dp */
562 | mRectBgCurrentTop =
563 | (int) (mPage1RectBgDefaultTop + FIRST_TOP1 + (FIRST_TOP2 * (positionOffset - FIRST_RATE) * 1.0 / (1 - FIRST_RATE)));
564 | }
565 |
566 | private void stepByShowPage2Views(float positionOffset) {
567 | /** 第2页,顶部图,跟随矩形背景下移 */
568 | mPage2Top.currentTop = mRectBgCurrentTop + padding();
569 |
570 | /** 第2页,底部图,跟随矩形背景下移 */
571 | mPage2Bottom.currentTop = mPage2Center[0].currentTop + mPage2Center[0].defaultHeight + padding();
572 |
573 | /** 第2页,计算裂变背景图的偏移px,并修改透明度渐变显示 */
574 | float offset =
575 | (mPage1RectBgDefaultWidth + dp2px(15)) * ((positionOffset - FIRST_RATE) * (1 / (1 - FIRST_RATE)));
576 | mPage2Split[0].currentLeft = mPage2Split[0].defaultLeft - offset;
577 | mPage2Split[1].currentLeft = mPage2Split[0].defaultLeft + offset;
578 | /**
579 | * 偏移到50%的时候alpha需要为0,偏移到100%,alpha需要为255,不过此时positionOffset的取值=0.5~1
580 | *
581 | * offset=0.5
582 | * 255 * (0.5 - 0.5) * (1 / (1 - 0.5)))=255 * 0 = 0
583 | *
584 | * offset=0.75
585 | * 255 * (0.75 - 0.5) * (1 / (1 - 0.5)))=255 * 0.5 = 127.5
586 | *
587 | * offset=1
588 | * 255 * (1 - 0.5) * (1 / (1 - 0.5)))=255 * 1 = 255
589 | */
590 | mPage2Split[0].alpha((int) (255 * (positionOffset - FIRST_RATE) * (1 / (1 - FIRST_RATE))));
591 | mPage2Split[1].alpha((int) (255 * (positionOffset - FIRST_RATE) * (1 / (1 - FIRST_RATE))));
592 |
593 | /** 第2页,顶部,底部图,透明度渐变显示,偏移量达到100%,完成显示 */
594 | mPage2Top.alpha((int) (255 * (positionOffset - FIRST_RATE) * (1 / (1 - FIRST_RATE))));
595 | mPage2Bottom.alpha((int) (255 * (positionOffset - FIRST_RATE) * (1 / (1 - FIRST_RATE))));
596 |
597 | /** 第2页,显示中间3张模特图 */
598 | for (int i = 0; i < mPage2Center.length; i++) {
599 | if (i == 0) {
600 | /** 第2页,显示第1张模特图 */
601 | mPage2Center[i].currentWidth =
602 | mPage2Center[i].defaultWidth * (positionOffset - FIRST_RATE) * 1 / (1 - FIRST_RATE);
603 | mPage2Center[i].currentHeight =
604 | mPage2Center[i].defaultHeight * (positionOffset - FIRST_RATE) * 1 / (1 - FIRST_RATE);
605 | mPage2Center[i].alpha((int) (255 * (positionOffset - FIRST_RATE) * (1 / (1 - FIRST_RATE))));
606 | mPage2Center[i].currentTop = mPage2Top.currentTop + mPage2Top.currentHeight + padding();
607 | } else {
608 | /** 第2,3张模特图,在前1张显示到一半时才显示 */
609 | if (mPage2Center[i - 1].currentWidth >= mPage2Center[i - 1].defaultWidth / 2) {
610 | float rate = mPage2Center[i - 1].widthRate() - 0.5f;
611 | mPage2Center[i].currentWidth = mPage2Center[i].defaultWidth * (rate * 2);
612 | mPage2Center[i].currentHeight = mPage2Center[i].defaultHeight * (rate * 2);
613 | /** 第2,3张模特图,需要根据第1张图计算left */
614 | mPage2Center[i].currentLeft =
615 | mPage2Center[0].currentLeft + mPage2Center[0].currentWidth + padding();
616 | mPage2Center[i].currentTop = mPage2Top.currentTop + mPage2Top.currentHeight + padding();
617 | if (i == 2) {
618 | /** 第3张模特图,根据第2张图计算top */
619 | mPage2Center[i].currentTop =
620 | mPage2Center[1].currentTop + mPage2Center[1].currentHeight + padding();
621 | }
622 | mPage2Center[i].alpha((int) (255 * (positionOffset * rate * 2)));
623 | } else {
624 | mPage2Center[i].alpha(0);
625 | }
626 | }
627 | }
628 | }
629 |
630 | private void transformRectBgFrom2To3(float positionOffset) {
631 | /** 快速滑动的时候,可能丢失最后一次绘制,所以需要在这里调重新设置一次,保证变化完成 */
632 | mRectBgCurrentHeight = mPage2RectBgDefaultHeight;
633 | mRectBgCurrentTop = mPage2RectBgDefaultTop;
634 |
635 | /** 矩形背景,宽度缩小15% */
636 | mRectBgCurrentWidth = (int) (mPage2RectBgDefaultWidth * (1 + SECOND_WIDTH * positionOffset));
637 | mRectBgCurrentLeft = getScreenWidth() / 2 - mRectBgCurrentWidth / 2;
638 |
639 | /** 矩形背景,上移20dp */
640 | mRectBgCurrentTop = (int) (mPage2RectBgDefaultTop + (SECOND_TOP * positionOffset));
641 | }
642 |
643 | private void stepByHidePage2Views(float positionOffset, int positionOffsetPixels) {
644 | /** 裂变背景图,跟随滑动,向左偏移至消失 */
645 | mPage2Split[0].currentLeft =
646 | (mPage2Split[0].defaultLeft - mPage1RectBgDefaultWidth - dp2px(15)) - positionOffsetPixels
647 | * (1 / SECOND_RATE);
648 | mPage2Split[1].currentLeft =
649 | (mPage2Split[1].defaultLeft + mPage1RectBgDefaultWidth + dp2px(15)) - positionOffsetPixels
650 | * (1 / SECOND_RATE);
651 | mPage2Split[0].alpha((int) (255 - (255 * positionOffset * (1 / SECOND_RATE))));
652 | mPage2Split[1].alpha((int) (255 - (255 * positionOffset * (1 / SECOND_RATE))));
653 |
654 | /** 顶部图,3张模特图,底部图,跟随矩形背景上移 */
655 | mPage2Top.currentTop = mRectBgCurrentTop + padding();
656 | mPage2Center[0].currentTop = mPage2Top.currentTop + mPage2Top.currentHeight + padding();
657 | mPage2Center[1].currentTop = mPage2Center[0].currentTop;
658 | mPage2Center[2].currentTop = mPage2Center[1].currentTop + mPage2Center[1].currentHeight;
659 | mPage2Bottom.currentTop = mPage2Center[0].currentTop + mPage2Center[0].currentHeight + padding();
660 |
661 | /** 渐渐减少透明度,隐藏第2页的顶部图,3张模特图,底部图 */
662 | mPage2Top.alpha((int) (255 - (255 * positionOffset * (1 / SECOND_RATE))));
663 | mPage2Bottom.alpha((int) (255 - (255 * positionOffset * (1 / SECOND_RATE))));
664 | for (ViewModel viewModel : mPage2Center) {
665 | viewModel.alpha((int) (255 - (255 * positionOffset * (1 / SECOND_RATE))));
666 | }
667 |
668 | /** 因为矩形背景变窄了,所以渐渐减少第2页顶部图,底部图的宽度,实现跟随矩形背景宽度变化 */
669 | mPage2Top.currentWidth = mRectBgCurrentWidth - padding() * 2;
670 | mPage2Top.currentLeft = mRectBgCurrentLeft + padding();
671 | mPage2Bottom.currentWidth = mRectBgCurrentWidth - padding() * 2;
672 | mPage2Bottom.currentLeft = mRectBgCurrentLeft + padding();
673 | mPage2Bottom.currentLeft = mRectBgCurrentLeft + padding();
674 |
675 | /** 因为矩形背景变窄了,所以渐渐减少第2,3张模特图的宽高,left和top,实现跟随矩形背景宽度变化 */
676 | mPage2Center[0].currentLeft = mRectBgCurrentLeft + padding();
677 | mPage2Center[1].currentWidth = mRectBgCurrentWidth - padding() * 3 - mPage2Center[0].defaultWidth;
678 | mPage2Center[1].currentHeight = mPage2Center[1].currentWidth;
679 | mPage2Center[1].currentLeft = mPage2Center[0].currentLeft + mPage2Center[0].defaultWidth + padding();
680 |
681 | mPage2Center[2].currentWidth = mRectBgCurrentWidth - padding() * 3 - mPage2Center[0].defaultWidth;
682 | mPage2Center[2].currentHeight = mPage2Center[2].currentWidth;
683 | mPage2Center[2].currentLeft = mPage2Center[0].currentLeft + mPage2Center[0].defaultWidth + padding();
684 | mPage2Center[2].currentTop = mPage2Center[1].currentTop + mPage2Center[1].currentHeight + padding();
685 | }
686 |
687 | private void stepByShowPage3Views(float positionOffset) {
688 | /** 第2页,在50->100%区间偏移,显示第3页,6张模特图 */
689 | for (int i = 0; i < mPage3Model.length; i++) {
690 | if (i == 0) {
691 | /** 第1张模特图先显示 */
692 | if (mPage3Model[i].paint.getAlpha() < 255) {
693 | mPage3Model[i].alpha((int) (255 * (positionOffset - SECOND_RATE) * (1 / (1 - SECOND_RATE))));
694 | }
695 | } else {
696 | /** 其他模特图在前1张显示50%透明度的时候再依次展示 */
697 | if (mPage3Model[i - 1].paint.getAlpha() >= 255 / 2) {
698 | float rate = mPage3Model[i - 1].paint.getAlpha() / 255.0f - 0.5f;
699 | mPage3Model[i].alpha((int) (255 * (rate * 2)));
700 | } else {
701 | mPage3Model[i].alpha(0);
702 | }
703 | }
704 |
705 | /** 6张模特图,跟随矩形背景上移 */
706 | if (i < mPage3ModelResources.length / 2) {
707 | /** 第1排,3张模特图的top计算 */
708 | mPage3Model[i].currentTop = mRectBgCurrentTop + padding();
709 | } else {
710 | /** 第1排,3张模特图的top,需要加上第一排的height */
711 | mPage3Model[i].currentTop = mRectBgCurrentTop + mPage3ModelDefaultHeight + padding() * 2;
712 | }
713 | }
714 | }
715 |
716 | private boolean isPage4(int currentPageIndex) {
717 | return currentPageIndex == 3;
718 | }
719 |
720 | private boolean fromPage3ToPage4(int position) {
721 | return position == 2;
722 | }
723 |
724 | private boolean fromPage2ToPage3(int position) {
725 | return position == 1;
726 | }
727 |
728 | private boolean fromPage1ToPage2(int position) {
729 | return position == 0;
730 | }
731 |
732 | private void hidePage4Views() {
733 | mPage4Top.alpha(0);
734 |
735 | for (ViewModel viewModel : mPage4Model) {
736 | viewModel.currentWidth = 0;
737 | viewModel.currentHeight = 0;
738 | viewModel.alpha(0);
739 | }
740 |
741 | for (ViewModel viewModel : mPage4Split) {
742 | viewModel.alpha(0);
743 | }
744 | }
745 |
746 | private void hidePage3Views() {
747 | for (int i = 0; i < mPage3Model.length; i++) {
748 | mPage3Model[i].alpha(0);
749 | }
750 | }
751 |
752 | private void scaleHidePage3Views() {
753 | for (int i = 0; i < mPage3Model.length; i++) {
754 | mPage3Model[i].currentWidth = 0;
755 | mPage3Model[i].currentHeight = 0;
756 | }
757 | }
758 |
759 | private void hidePage1Views() {
760 | mPage1Top.alpha(0);
761 | mPage1Bottom.alpha(0);
762 | }
763 |
764 | private void hidePage2Views() {
765 | mPage2Top.alpha(0);
766 | mPage2Bottom.alpha(0);
767 |
768 | for (ViewModel viewModel : mPage2Center) {
769 | viewModel.alpha(0);
770 | }
771 |
772 | for (ViewModel viewModel : mPage2Split) {
773 | viewModel.alpha(0);
774 | }
775 | }
776 |
777 | public void drawBitmap(Canvas canvas, ViewModel viewModel) {
778 | canvas.drawBitmap(viewModel.bitmap, viewModel.currentLeft, viewModel.currentTop, viewModel.paint);
779 | }
780 |
781 | public void drawBitmapMatrix(Canvas canvas, ViewModel viewModel) {
782 | canvas.drawBitmap(viewModel.bitmap, viewModel.matrix, viewModel.paint);
783 | }
784 |
785 | public void drawBitmapRect(Canvas canvas, ViewModel viewModel) {
786 | RectF rect = new RectF();
787 | rect.left = viewModel.currentLeft;
788 | rect.top = viewModel.currentTop;
789 | rect.right = rect.left + viewModel.currentWidth;
790 | rect.bottom = rect.top + viewModel.currentHeight;
791 | canvas.drawBitmap(viewModel.bitmap, null, rect, viewModel.paint);
792 | }
793 |
794 | /**
795 | * @desc 根据当前页面,绘制不同的view
796 | * @author listen
797 | */
798 | @Override
799 | protected void onDraw(Canvas canvas) {
800 | super.onDraw(canvas);
801 |
802 | /** 按重叠顺序绘制 */
803 | if (fromPage1ToPage2(mCurrentPageIndex)) {
804 |
805 | /** 绘制第1页,底部背景图 */
806 | drawBitmap(canvas, mPage1BottomBg);
807 |
808 | /** 绘制第2页,裂变背景图 */
809 | drawBitmap(canvas, mPage2Split[0]);
810 | drawBitmap(canvas, mPage2Split[1]);
811 |
812 | /** 绘制白色矩形背景 */
813 | drawWhiteRectBackgroud(canvas);
814 |
815 | drawPage1InCanvas(canvas);
816 | drawPage2InCanvas(canvas);
817 |
818 | } else if (fromPage2ToPage3(mCurrentPageIndex)) {
819 |
820 | /** 绘制第2页,裂变背景图 */
821 | drawBitmap(canvas, mPage2Split[0]);
822 | drawBitmap(canvas, mPage2Split[1]);
823 |
824 | /** 绘制矩形背景 */
825 | drawWhiteRectBackgroud(canvas);
826 |
827 | drawPage2InCanvas(canvas);
828 | drawPage3InCanvas(canvas);
829 |
830 | } else if (fromPage3ToPage4(mCurrentPageIndex)) {
831 | /** 绘制第4页,裂变背景图 */
832 | drawBitmapMatrix(canvas, mPage4Split[0]);
833 | drawBitmapMatrix(canvas, mPage4Split[1]);
834 |
835 | /** 绘制矩形背景 */
836 | drawWhiteRectBackgroud(canvas);
837 |
838 | drawPage3InCanvas(canvas);
839 | drawPage4InCanvas(canvas);
840 |
841 | } else if (isPage4(mCurrentPageIndex)) {
842 |
843 | /** 绘制第4页,裂变背景图 */
844 | drawBitmapMatrix(canvas, mPage4Split[0]);
845 | drawBitmapMatrix(canvas, mPage4Split[1]);
846 |
847 | /** 绘制矩形背景 */
848 | drawWhiteRectBackgroud(canvas);
849 |
850 | drawPage4InCanvas(canvas);
851 | }
852 | }
853 |
854 | private void drawPage1InCanvas(Canvas canvas) {
855 | /** 绘制第1页,顶部模特图 */
856 | drawBitmap(canvas, mPage1Top);
857 |
858 | /** 绘制第1页,底部文案图 */
859 | drawBitmap(canvas, mPage1Bottom);
860 | }
861 |
862 | private void drawPage4InCanvas(Canvas canvas) {
863 | /** 绘制第4页,顶部模特图 */
864 | drawBitmap(canvas, mPage4Top);
865 |
866 | /** 绘制第4页,底部3张模特图 */
867 | for (int i = 0; i < mPage4Model.length; i++) {
868 | drawBitmapRect(canvas, mPage4Model[i]);
869 | }
870 | }
871 |
872 | private void drawPage3InCanvas(Canvas canvas) {
873 | /** 绘制第3页,6张模特图 */
874 | for (int i = 0; i < mPage3Model.length; i++) {
875 | drawBitmapRect(canvas, mPage3Model[i]);
876 | }
877 | }
878 |
879 | private void drawPage2InCanvas(Canvas canvas) {
880 | /** 绘制第2页,顶部图 */
881 | drawBitmapRect(canvas, mPage2Top);
882 |
883 | /** 绘制第2页,第1张模特图 */
884 | drawBitmapRect(canvas, mPage2Center[0]);
885 | /** 在第1张模特图绘制到50%时,绘制第2张模特图 */
886 | if (mPage2Center[0].currentWidth >= mPage2Center[0].defaultWidth / 2) {
887 | drawBitmapRect(canvas, mPage2Center[1]);
888 | /** 在第2张模特图绘制到50%时,绘制第3张模特图 */
889 | if (mPage2Center[1].currentWidth >= mPage2Center[1].defaultWidth / 2) {
890 | drawBitmapRect(canvas, mPage2Center[2]);
891 | }
892 | }
893 |
894 | /** 绘制第2页,底部图 */
895 | drawBitmapRect(canvas, mPage2Bottom);
896 | }
897 |
898 | @NonNull
899 | private RectF drawWhiteRectBackgroud(Canvas canvas) {
900 | RectF rect = new RectF();
901 | rect.left = mRectBgCurrentLeft;
902 | rect.top = mRectBgCurrentTop;
903 | rect.right = rect.left + mRectBgCurrentWidth;
904 | rect.bottom = rect.top + mRectBgCurrentHeight;
905 |
906 | canvas.rotate(mRectBgCurrentDegree, rect.left + mRectBgCurrentWidth / 2, rect.top + mRectBgCurrentHeight / 2);
907 | canvas.drawRoundRect(rect, mRectBgDefaultCorner, mRectBgDefaultCorner, mRectBgPaint);
908 | return rect;
909 | }
910 |
911 | private int padding() {
912 | return dp2px(5);
913 | }
914 |
915 | public int getScreenWidth() {
916 | if (null != getResources() && null != getResources().getDisplayMetrics()) {
917 | return getResources().getDisplayMetrics().widthPixels;
918 | }
919 | return 0;
920 | }
921 |
922 | public int getScreenHeight() {
923 | if (null != getResources() && null != getResources().getDisplayMetrics()) {
924 | return getResources().getDisplayMetrics().heightPixels;
925 | }
926 | return 0;
927 | }
928 |
929 | public int dp2px(float dpValue) {
930 | final float scale = getResources().getDisplayMetrics().density;
931 | return (int) (dpValue * scale + 0.5f);
932 | }
933 |
934 | }
935 |
--------------------------------------------------------------------------------
/app/src/main/java/com/listen/test_mogu_view/viewpager/TransforViewTag1.java:
--------------------------------------------------------------------------------
1 | package com.listen.test_mogu_view.viewpager;
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.RectF;
8 | import android.support.annotation.NonNull;
9 | import android.util.AttributeSet;
10 | import android.util.Log;
11 | import android.view.View;
12 |
13 | public class TransforViewTag1 extends View {
14 |
15 | // /////////////////////////////////////////////////////////////////////////
16 | // 页面切换时的,白色矩形背景的变化参数
17 | // /////////////////////////////////////////////////////////////////////////
18 | /**
19 | * 第1页->第2页
20 | */
21 | public static final float FIRST_HEIGHT = 0.4f;// 第1个页面高度缩放比例,正:放大,负:缩小
22 | public final int FIRST_TOP1 = -dp2px(30);// 第1个页面top移动距离,正:下移,负:上移
23 | public final int FIRST_TOP2 = dp2px(60);// 第1个页面top移动距离,正:下移,负:上移
24 | public static final float FIRST_RATE = 0.5f;// 在偏移50%处,进行下一页的显示
25 | /**
26 | * 第2页->第3页
27 | */
28 | public static final float SECOND_WIDTH = -0.15f;// 第2个页面宽度缩放比例,正:放大,负:缩小
29 | public final int SECOND_TOP = -dp2px(20);// 第2个页面top移动距离比例,正:下移,负:上移
30 | public static final float SECOND_RATE = 0.5f;// 在偏移50%处,进行下一页的显示
31 | /**
32 | * 第3页->第4页
33 | */
34 | public static final float THIRD_WIDTH = -0.1f;// 第3个页面宽度缩放比例,正:放大,负:缩小
35 | public static final float THIRD_HEIGHT = -0.1f;// 第3个页面高度缩放比例,正:放大,负:缩小
36 | public static final int THIRD_DEGREE = -10;// 第3个页面角度调整,正:顺时针,负:逆时针
37 | public static final float THIRD_RATE = 0.5f;// 在偏移50%处,进行下一页的显示
38 |
39 | // /////////////////////////////////////////////////////////////////////////
40 | // 白色圆角矩形背景
41 | // /////////////////////////////////////////////////////////////////////////
42 | private Paint mRectBgPaint;
43 | private int mRectBgDefaultCorner = dp2px(5);// 初始圆角5dp
44 | private float mRectBgCurrentDegree = 0;// 默认不旋转
45 |
46 | /**
47 | * 第1页初始化
48 | * default=默认初始宽高,left,top,如果是2,3,4页,则表示变化后的值
49 | * current=当前宽高,left,top,会根据偏移量变化
50 | */
51 | private float mPage1RectBgDefaultWidth = dp2px(260);
52 | private float mPage1RectBgDefaultHeight = dp2px(230);
53 | private float mPage1RectBgDefaultLeft = getScreenWidth() / 2 - mPage1RectBgDefaultWidth / 2;
54 | private float mPage1RectBgDefaultTop = dp2px(80);
55 |
56 | private float mRectBgCurrentWidth = mPage1RectBgDefaultWidth;
57 | private float mRectBgCurrentHeight = mPage1RectBgDefaultHeight;
58 | private float mRectBgCurrentLeft = mPage1RectBgDefaultLeft;
59 | private float mRectBgCurrentTop = mPage1RectBgDefaultTop;
60 |
61 | /**
62 | * 第1页->第2页
63 | * 在第1页的基础上进行变化
64 | * 1.height放大
65 | * 2.top先上移n,在下移n*2
66 | */
67 | private float mPage2RectBgDefaultWidth = mPage1RectBgDefaultWidth;
68 | private float mPage2RectBgDefaultHeight = mPage1RectBgDefaultHeight * (1 + FIRST_HEIGHT);
69 | private float mPage2RectBgDefaultLeft = mPage1RectBgDefaultLeft;
70 | private float mPage2RectBgDefaultTop = mPage1RectBgDefaultTop + FIRST_TOP1 + FIRST_TOP2;
71 |
72 | /**
73 | * 第2页->第3页
74 | * 在第2页的基础上进行变化
75 | * 1.宽度缩小
76 | * 2.top上移
77 | */
78 | private float mPage3RectBgDefaultWidth = mPage2RectBgDefaultWidth * (1 + SECOND_WIDTH);
79 | private float mPage3RectBgDefaultHeight = mPage2RectBgDefaultHeight;
80 | private float mPage3RectBgDefaultLeft = getScreenWidth() / 2 - mPage3RectBgDefaultWidth / 2;
81 | private float mPage3RectBgDefaultTop = mPage2RectBgDefaultTop + SECOND_TOP;
82 |
83 | /**
84 | * 第3页->第4页
85 | * 在第3页的基础上进行变化
86 | * 1.宽度缩小
87 | * 2.高度缩小
88 | * 2.逆时针旋转
89 | */
90 | private float mPage4RectBgDefaultWidth = mPage3RectBgDefaultWidth * (1 + THIRD_WIDTH);
91 | private float mPage4RectBgDefaultHeight = mPage3RectBgDefaultHeight * (1 + THIRD_HEIGHT);
92 | private float mPage4RectBgDefaultLeft = getScreenWidth() / 2 - mPage4RectBgDefaultWidth / 2;
93 | private float mPage4RectBgDefaultTop = mPage3RectBgDefaultTop;
94 | private float mPage4ModelDefaultWidth = (mPage4RectBgDefaultWidth - padding() * 4) / 3;
95 |
96 | /**
97 | * 当前页数索引
98 | */
99 | private int mCurrentPageIndex;
100 |
101 | public TransforViewTag1(Context context) {
102 | super(context);
103 | init();
104 | }
105 |
106 | public TransforViewTag1(Context context, AttributeSet attrs) {
107 | super(context, attrs);
108 | init();
109 | }
110 |
111 | public TransforViewTag1(Context context, AttributeSet attrs, int defStyle) {
112 | super(context, attrs, defStyle);
113 | init();
114 | }
115 |
116 | public void transfor(int position, float positionOffset, int positionOffsetPixels) {
117 | Log.e("ls_debug_log", "p=" + position + ",p_offset=" + positionOffset + ",p_px=" + positionOffsetPixels);
118 | mCurrentPageIndex = position;
119 | calculateOffset(position, positionOffset, positionOffsetPixels);
120 | }
121 |
122 | private void init() {
123 | /** 第1页,初始化矩形背景 */
124 | mRectBgPaint = new Paint();
125 | mRectBgPaint.setAntiAlias(true); // 设置画笔为无锯齿
126 | mRectBgPaint.setColor(Color.BLACK); // 设置画笔颜色
127 | mRectBgPaint.setStyle(Paint.Style.FILL); // 空心效果
128 | }
129 |
130 | /**
131 | * @desc 根据viewPager偏移,修改view的宽,高,left,top
132 | * @author listen
133 | */
134 | private void calculateOffset(int position, float positionOffset, int positionOffsetPixels) {
135 | if (fromPage1ToPage2(position)) {
136 | if (positionOffset < FIRST_RATE) {
137 | /** 第1页,在0->50%区间偏移 */
138 | /** 矩形背景,高度放大40%,向上移动30dp */
139 | transformRectBgFrom1To2Before(positionOffset);
140 |
141 | } else {
142 | /** 第1页,在50%->100%区间偏移 */
143 | /** 矩形背景,上移30dp后,向下偏移60dp */
144 | transformRectBgFrom1To2After(positionOffset);
145 |
146 | }
147 | } else if (fromPage2ToPage3(position)) {
148 | /** 矩形背景,宽度缩小15%,上移20dp */
149 | transformRectBgFrom2To3(positionOffset);
150 |
151 | } else if (fromPage3ToPage4(position)) {
152 | /** 背景矩形的宽度,高度减少10%,逆时针旋转10度 */
153 | transformRectBgFrom3To4(positionOffset);
154 | }
155 | postInvalidate();
156 | }
157 |
158 | private void transformRectBgFrom1To2After(float positionOffset) {
159 | /** 快速滑动的时候,可能丢失最后一次绘制,所以需要在这里调重新设置一次,保证变化完成 */
160 | mRectBgCurrentHeight = mPage2RectBgDefaultHeight;
161 | mRectBgCurrentTop = mPage1RectBgDefaultTop + FIRST_TOP1;
162 | /** 第1页,在50%->100%区间偏移 */
163 | /** 矩形背景,在上上偏移30dp后,向下偏移60dp */
164 | mRectBgCurrentTop =
165 | (int) (mPage1RectBgDefaultTop + FIRST_TOP1 + (FIRST_TOP2 * (positionOffset - FIRST_RATE) * 1.0 / (1 - FIRST_RATE)));
166 | }
167 |
168 | private void transformRectBgFrom2To3(float positionOffset) {
169 | /** 快速滑动的时候,可能丢失最后一次绘制,所以需要在这里调重新设置一次,保证变化完成 */
170 | mRectBgCurrentHeight = mPage2RectBgDefaultHeight;
171 | mRectBgCurrentTop = mPage2RectBgDefaultTop;
172 |
173 | /** 矩形背景,宽度缩小15% */
174 | mRectBgCurrentWidth = (int) (mPage2RectBgDefaultWidth * (1 + SECOND_WIDTH * positionOffset));
175 | mRectBgCurrentLeft = getScreenWidth() / 2 - mRectBgCurrentWidth / 2;
176 |
177 | /** 矩形背景,上移20dp */
178 | mRectBgCurrentTop = (int) (mPage2RectBgDefaultTop + (SECOND_TOP * positionOffset));
179 | }
180 |
181 | private void transformRectBgFrom3To4(float positionOffset) {
182 | /** 快速滑动的时候,可能丢失最后一次绘制,所以需要在这里调重新设置一次,保证变化完成 */
183 | mRectBgCurrentWidth = mPage3RectBgDefaultWidth;
184 | mRectBgCurrentTop = mPage3RectBgDefaultTop;
185 |
186 | /** 调整第4页,背景矩形的宽高和角度 */
187 | /** 背景矩形的宽度,在第3页调整宽度的基础上进行缩小 */
188 | mRectBgCurrentWidth = mPage3RectBgDefaultWidth * (1 + THIRD_WIDTH * positionOffset);
189 | mRectBgCurrentLeft = getScreenWidth() / 2 - mRectBgCurrentWidth / 2;
190 | /** 背景矩形的高度,在第2页调整高度的基础上进行缩小 */
191 | mRectBgCurrentHeight = mPage3RectBgDefaultHeight * (1 + THIRD_HEIGHT * positionOffset);
192 | /** 背景矩形逆时针旋转 */
193 | mRectBgCurrentDegree = THIRD_DEGREE * positionOffset;
194 | }
195 |
196 | private void transformRectBgFrom1To2Before(float positionOffset) {
197 | /** 矩形背景,高度放大40% */
198 | /**
199 | * 偏移到50%的时候height需要放大40%,defaultHeight=400,targetHeight=400*1.4=560
200 | *
201 | * offset=0
202 | * 400 * (1 + 0.4 * 0 * (1 / 0.5)) = 400
203 | *
204 | * offset=0.25
205 | * 400 * (1 + 0.4 * 0.25 * (1 / 0.5)) = 400 * 1.2 = 480
206 | *
207 | * offset=0.5
208 | * 400 * (1 + 0.4 * 0.5 * (1 / 0.5)) = 400 * 1.4 = 560
209 | *
210 | */
211 | mRectBgCurrentHeight =
212 | (int) (mPage1RectBgDefaultHeight * (1 + FIRST_HEIGHT * positionOffset * (1 / FIRST_RATE)));
213 | /** 矩形背景,向上移动30dp */
214 | mRectBgCurrentTop = (int) (mPage1RectBgDefaultTop + (FIRST_TOP1 * positionOffset * (1 / FIRST_RATE)));
215 | }
216 |
217 | private boolean isPage4(int currentPageIndex) {
218 | return currentPageIndex == 3;
219 | }
220 |
221 | private boolean fromPage3ToPage4(int position) {
222 | return position == 2;
223 | }
224 |
225 | private boolean fromPage2ToPage3(int position) {
226 | return position == 1;
227 | }
228 |
229 | private boolean fromPage1ToPage2(int position) {
230 | return position == 0;
231 | }
232 |
233 | public void drawBitmap(Canvas canvas, ViewModel viewModel) {
234 | canvas.drawBitmap(viewModel.bitmap, viewModel.currentLeft, viewModel.currentTop, viewModel.paint);
235 | }
236 |
237 | public void drawBitmapMatrix(Canvas canvas, ViewModel viewModel) {
238 | canvas.drawBitmap(viewModel.bitmap, viewModel.matrix, viewModel.paint);
239 | }
240 |
241 |
242 | public void drawBitmapRect(Canvas canvas, ViewModel viewModel) {
243 | RectF rect = new RectF();
244 | rect.left = viewModel.currentLeft;
245 | rect.top = viewModel.currentTop;
246 | rect.right = rect.left + viewModel.currentWidth;
247 | rect.bottom = rect.top + viewModel.currentHeight;
248 | canvas.drawBitmap(viewModel.bitmap, null, rect, viewModel.paint);
249 | }
250 |
251 | /**
252 | * @desc 根据当前页面,绘制不同的view
253 | * @author listen
254 | */
255 | @Override
256 | protected void onDraw(Canvas canvas) {
257 | super.onDraw(canvas);
258 | /** 绘制白色矩形背景 */
259 | // drawWhiteRectBackgroud(canvas);
260 |
261 | RectF rect = new RectF();
262 | rect.left = mRectBgCurrentLeft;
263 | rect.top = mRectBgCurrentTop;
264 | rect.right = rect.left + mRectBgCurrentWidth;
265 | rect.bottom = rect.top + mRectBgCurrentHeight;
266 |
267 | canvas.rotate(mRectBgCurrentDegree, rect.left + mRectBgCurrentWidth / 2, rect.top + mRectBgCurrentHeight / 2);
268 | canvas.drawRoundRect(rect, mRectBgDefaultCorner, mRectBgDefaultCorner, mRectBgPaint);
269 | }
270 |
271 | @NonNull
272 | private RectF drawWhiteRectBackgroud(Canvas canvas) {
273 | RectF rect = new RectF();
274 | rect.left = mRectBgCurrentLeft;
275 | rect.top = mRectBgCurrentTop;
276 | rect.right = rect.left + mRectBgCurrentWidth;
277 | rect.bottom = rect.top + mRectBgCurrentHeight;
278 |
279 | canvas.rotate(mRectBgCurrentDegree, rect.left + mRectBgCurrentWidth / 2, rect.top + mRectBgCurrentHeight / 2);
280 | canvas.drawRoundRect(rect, mRectBgDefaultCorner, mRectBgDefaultCorner, mRectBgPaint);
281 | return rect;
282 | }
283 |
284 | private int padding() {
285 | return dp2px(5);
286 | }
287 |
288 | public int getScreenWidth() {
289 | if (null != getResources() && null != getResources().getDisplayMetrics()) {
290 | return getResources().getDisplayMetrics().widthPixels;
291 | }
292 | return 0;
293 | }
294 |
295 |
296 |
297 | public int dp2px(float dpValue) {
298 | final float scale = getResources().getDisplayMetrics().density;
299 | return (int) (dpValue * scale + 0.5f);
300 | }
301 |
302 | }
303 |
--------------------------------------------------------------------------------
/app/src/main/java/com/listen/test_mogu_view/viewpager/TransforViewTag2.java:
--------------------------------------------------------------------------------
1 | package com.listen.test_mogu_view.viewpager;
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.RectF;
8 | import android.support.annotation.NonNull;
9 | import android.util.AttributeSet;
10 | import android.util.Log;
11 | import android.view.View;
12 |
13 | import com.listen.test_mogu_view.R;
14 |
15 |
16 | public class TransforViewTag2 extends View {
17 |
18 | // /////////////////////////////////////////////////////////////////////////
19 | // 页面切换时的,白色矩形背景的变化参数
20 | // /////////////////////////////////////////////////////////////////////////
21 | /**
22 | * 第1页->第2页
23 | */
24 | public static final float FIRST_HEIGHT = 0.4f;// 第1个页面高度缩放比例,正:放大,负:缩小
25 | public final int FIRST_TOP1 = -dp2px(30);// 第1个页面top移动距离,正:下移,负:上移
26 | public final int FIRST_TOP2 = dp2px(60);// 第1个页面top移动距离,正:下移,负:上移
27 | public static final float FIRST_RATE = 0.5f;// 在偏移50%处,进行下一页的显示
28 | /**
29 | * 第2页->第3页
30 | */
31 | public static final float SECOND_WIDTH = -0.15f;// 第2个页面宽度缩放比例,正:放大,负:缩小
32 | public final int SECOND_TOP = -dp2px(20);// 第2个页面top移动距离比例,正:下移,负:上移
33 | public static final float SECOND_RATE = 0.5f;// 在偏移50%处,进行下一页的显示
34 | /**
35 | * 第3页->第4页
36 | */
37 | public static final float THIRD_WIDTH = -0.1f;// 第3个页面宽度缩放比例,正:放大,负:缩小
38 | public static final float THIRD_HEIGHT = -0.1f;// 第3个页面高度缩放比例,正:放大,负:缩小
39 | public static final int THIRD_DEGREE = -10;// 第3个页面角度调整,正:顺时针,负:逆时针
40 | public static final float THIRD_RATE = 0.5f;// 在偏移50%处,进行下一页的显示
41 |
42 | // /////////////////////////////////////////////////////////////////////////
43 | // 白色圆角矩形背景
44 | // /////////////////////////////////////////////////////////////////////////
45 | private Paint mRectBgPaint;
46 | private int mRectBgDefaultCorner = dp2px(5);// 初始圆角5dp
47 | private float mRectBgCurrentDegree = 0;// 默认不旋转
48 |
49 | /**
50 | * 第1页初始化
51 | * default=默认初始宽高,left,top,如果是2,3,4页,则表示变化后的值
52 | * current=当前宽高,left,top,会根据偏移量变化
53 | */
54 | private float mPage1RectBgDefaultWidth = dp2px(260);
55 | private float mPage1RectBgDefaultHeight = dp2px(230);
56 | private float mPage1RectBgDefaultLeft = getScreenWidth() / 2 - mPage1RectBgDefaultWidth / 2;
57 | private float mPage1RectBgDefaultTop = dp2px(80);
58 |
59 | private float mRectBgCurrentWidth = mPage1RectBgDefaultWidth;
60 | private float mRectBgCurrentHeight = mPage1RectBgDefaultHeight;
61 | private float mRectBgCurrentLeft = mPage1RectBgDefaultLeft;
62 | private float mRectBgCurrentTop = mPage1RectBgDefaultTop;
63 |
64 | /**
65 | * 第1页->第2页
66 | * 在第1页的基础上进行变化
67 | * 1.height放大
68 | * 2.top先上移n,在下移n*2
69 | */
70 | private float mPage2RectBgDefaultWidth = mPage1RectBgDefaultWidth;
71 | private float mPage2RectBgDefaultHeight = mPage1RectBgDefaultHeight * (1 + FIRST_HEIGHT);
72 | private float mPage2RectBgDefaultLeft = mPage1RectBgDefaultLeft;
73 | private float mPage2RectBgDefaultTop = mPage1RectBgDefaultTop + FIRST_TOP1 + FIRST_TOP2;
74 |
75 | /**
76 | * 第2页->第3页
77 | * 在第2页的基础上进行变化
78 | * 1.宽度缩小
79 | * 2.top上移
80 | */
81 | private float mPage3RectBgDefaultWidth = mPage2RectBgDefaultWidth * (1 + SECOND_WIDTH);
82 | private float mPage3RectBgDefaultHeight = mPage2RectBgDefaultHeight;
83 | private float mPage3RectBgDefaultLeft = getScreenWidth() / 2 - mPage3RectBgDefaultWidth / 2;
84 | private float mPage3RectBgDefaultTop = mPage2RectBgDefaultTop + SECOND_TOP;
85 |
86 | /**
87 | * 第3页->第4页
88 | * 在第3页的基础上进行变化
89 | * 1.宽度缩小
90 | * 2.高度缩小
91 | * 2.逆时针旋转
92 | */
93 | private float mPage4RectBgDefaultWidth = mPage3RectBgDefaultWidth * (1 + THIRD_WIDTH);
94 | private float mPage4RectBgDefaultHeight = mPage3RectBgDefaultHeight * (1 + THIRD_HEIGHT);
95 | private float mPage4RectBgDefaultLeft = getScreenWidth() / 2 - mPage4RectBgDefaultWidth / 2;
96 | private float mPage4RectBgDefaultTop = mPage3RectBgDefaultTop;
97 | private float mPage4ModelDefaultWidth = (mPage4RectBgDefaultWidth - padding() * 4) / 3;
98 |
99 | // /////////////////////////////////////////////////////////////////////////
100 | // 第1页,view元素
101 | // /////////////////////////////////////////////////////////////////////////
102 | private ViewModel mPage1BottomBg;// 底部背景图
103 |
104 | // /////////////////////////////////////////////////////////////////////////
105 | // 第2页,view元素
106 | // /////////////////////////////////////////////////////////////////////////
107 | private ViewModel[] mPage2Split = new ViewModel[2];// 2张裂变背景图
108 |
109 | // /////////////////////////////////////////////////////////////////////////
110 | // 第4页,view元素
111 | // /////////////////////////////////////////////////////////////////////////
112 | private ViewModel[] mPage4Split = new ViewModel[2];// 2张裂变背景图
113 |
114 | /**
115 | * 当前页数索引
116 | */
117 | private int mCurrentPageIndex;
118 |
119 | public TransforViewTag2(Context context) {
120 | super(context);
121 | init();
122 | }
123 |
124 | public TransforViewTag2(Context context, AttributeSet attrs) {
125 | super(context, attrs);
126 | init();
127 | }
128 |
129 | public TransforViewTag2(Context context, AttributeSet attrs, int defStyle) {
130 | super(context, attrs, defStyle);
131 | init();
132 | }
133 |
134 | public void transfor(int position, float positionOffset, int positionOffsetPixels) {
135 | Log.e("ls_debug_log", "p=" + position + ",p_offset=" + positionOffset + ",p_px=" + positionOffsetPixels);
136 | mCurrentPageIndex = position;
137 | calculateOffset(position, positionOffset, positionOffsetPixels);
138 | }
139 |
140 | private void init() {
141 | {
142 | /** 第1页,初始化矩形背景 */
143 | mRectBgPaint = new Paint();
144 | mRectBgPaint.setAntiAlias(true); // 设置画笔为无锯齿
145 | mRectBgPaint.setColor(Color.BLACK); // 设置画笔颜色
146 | mRectBgPaint.setStyle(Paint.Style.FILL); // 空心效果
147 | }
148 | /** 第1页,底部背景图 */
149 | mPage1BottomBg =
150 | new ViewModel(getContext(), R.drawable.one_bottom_bg).alpha(255)
151 | .width(mPage1RectBgDefaultWidth - padding() * 2)
152 | // .height()// 不传则按宽度比例缩放
153 | .left(mPage1RectBgDefaultLeft + padding())
154 | // top距离=矩形背景top+height+5dp边距
155 | .top(mPage1RectBgDefaultTop + mPage1RectBgDefaultHeight + padding())
156 | .create();
157 |
158 | /** 第2页,裂变背景图 */
159 | for (int i = 0; i < 2; i++) {
160 | mPage2Split[i] =
161 | new ViewModel(getContext(), R.drawable.two_bg).width(mPage2RectBgDefaultWidth)
162 | .height(mPage2RectBgDefaultHeight)
163 | .left(mPage2RectBgDefaultLeft)
164 | .top(mPage2RectBgDefaultTop)
165 | .create();
166 | }
167 | /** 第4页,2张裂变背景图 */
168 | for (int i = 0; i < mPage4Split.length; i++) {
169 | mPage4Split[i] =
170 | new ViewModel(getContext(), R.drawable.four_bg)
171 | .width(mPage4RectBgDefaultWidth)
172 | .height(mPage4RectBgDefaultHeight)
173 | .left(mPage4RectBgDefaultLeft)
174 | .top(mPage4RectBgDefaultTop);
175 |
176 | }
177 | }
178 |
179 | /**
180 | * @desc 根据viewPager偏移,修改view的宽,高,left,top
181 | * @author listen
182 | */
183 | private void calculateOffset(int position, float positionOffset, int positionOffsetPixels) {
184 | if (fromPage1ToPage2(position)) {
185 | /** 第1页,底部背景图,根据页面向左偏移 */
186 | mPage1BottomBg.currentLeft = mPage1BottomBg.defaultLeft - positionOffsetPixels;
187 |
188 | if (positionOffset < FIRST_RATE) {
189 | /** 第1页,在0->50%区间偏移 */
190 | /** 矩形背景,高度放大40%,向上移动30dp */
191 | transformRectBgFrom1To2Before(positionOffset);
192 |
193 | } else {
194 | /** 第1页,在50%->100%区间偏移 */
195 | /** 矩形背景,上移30dp后,向下偏移60dp */
196 | transformRectBgFrom1To2After(positionOffset);
197 |
198 | /** 第2页,渐渐裂变背景图 */
199 | stepByShowPage2Views(positionOffset);
200 | }
201 | } else if (fromPage2ToPage3(position)) {
202 | /** 矩形背景,宽度缩小15%,上移20dp */
203 | transformRectBgFrom2To3(positionOffset);
204 |
205 | if (positionOffset < SECOND_RATE) {
206 | /** 第2页,在0->50%区间偏移,渐渐隐藏裂变背景图 */
207 | stepByHidePage2Views(positionOffset, positionOffsetPixels);
208 | }
209 | } else if (fromPage3ToPage4(position)) {
210 |
211 | /** 背景矩形的宽度,高度减少10%,逆时针旋转10度 */
212 | transformRectBgFrom3To4(positionOffset);
213 |
214 | if (positionOffset < THIRD_RATE) {
215 |
216 | } else {
217 | /** 渐渐显示第4页,裂变背景图 */
218 | stepByShowPage4Views(positionOffset);
219 | }
220 | }
221 | postInvalidate();
222 | }
223 |
224 | private void stepByShowPage4Views(float positionOffset) {
225 | /** 显示第4页,裂变背景图,并向左右平移 */
226 | float offset = (mPage4RectBgDefaultWidth + dp2px(40)) * ((positionOffset - THIRD_RATE) * (1 / (1 - THIRD_RATE)));
227 | for (int i = 0; i < mPage4Split.length; i++) {
228 | mPage4Split[i].matrix.reset();
229 | mPage4Split[i].matrix.postScale(mPage4RectBgDefaultWidth / mPage4Split[i].bitmap.getWidth(), mPage4RectBgDefaultHeight / mPage4Split[i].bitmap.getHeight());
230 |
231 | float currentLeft = 0;
232 | if (i == 0) {
233 | // 左移
234 | currentLeft = mPage4RectBgDefaultLeft - offset;
235 | } else if (i == 1) {
236 | // 右移
237 | currentLeft = mPage4RectBgDefaultLeft + offset;
238 | }
239 |
240 | // 平移
241 | mPage4Split[i].matrix.postTranslate(currentLeft, mPage4RectBgDefaultTop);
242 | // 旋转角度
243 | mPage4Split[i].matrix.postRotate(THIRD_DEGREE, currentLeft + mPage4RectBgDefaultWidth/2,
244 | mPage4RectBgDefaultTop + mPage4RectBgDefaultHeight/2);
245 |
246 | mPage4Split[i].alpha((int) (255 * ((positionOffset - THIRD_RATE) * (1 / (1 - THIRD_RATE)))));
247 | }
248 | }
249 |
250 | private void transformRectBgFrom3To4(float positionOffset) {
251 | /** 快速滑动的时候,可能丢失最后一次绘制,所以需要在这里调重新设置一次,保证变化完成 */
252 | mRectBgCurrentWidth = mPage3RectBgDefaultWidth;
253 | mRectBgCurrentTop = mPage3RectBgDefaultTop;
254 |
255 | /** 调整第4页,背景矩形的宽高和角度 */
256 | /** 背景矩形的宽度,在第3页调整宽度的基础上进行缩小 */
257 | mRectBgCurrentWidth = mPage3RectBgDefaultWidth * (1 + THIRD_WIDTH * positionOffset);
258 | mRectBgCurrentLeft = getScreenWidth() / 2 - mRectBgCurrentWidth / 2;
259 | /** 背景矩形的高度,在第2页调整高度的基础上进行缩小 */
260 | mRectBgCurrentHeight = mPage3RectBgDefaultHeight * (1 + THIRD_HEIGHT * positionOffset);
261 | /** 背景矩形逆时针旋转 */
262 | mRectBgCurrentDegree = THIRD_DEGREE * positionOffset;
263 | }
264 |
265 | private void transformRectBgFrom1To2Before(float positionOffset) {
266 | /** 矩形背景,高度放大40% */
267 | /**
268 | * 偏移到50%的时候height需要放大40%,defaultHeight=400,targetHeight=400*1.4=560
269 | *
270 | * offset=0
271 | * 400 * (1 + 0.4 * 0 * (1 / 0.5)) = 400
272 | *
273 | * offset=0.25
274 | * 400 * (1 + 0.4 * 0.25 * (1 / 0.5)) = 400 * 1.2 = 480
275 | *
276 | * offset=0.5
277 | * 400 * (1 + 0.4 * 0.5 * (1 / 0.5)) = 400 * 1.4 = 560
278 | *
279 | */
280 | mRectBgCurrentHeight =
281 | (int) (mPage1RectBgDefaultHeight * (1 + FIRST_HEIGHT * positionOffset * (1 / FIRST_RATE)));
282 | /** 矩形背景,向上移动30dp */
283 | mRectBgCurrentTop = (int) (mPage1RectBgDefaultTop + (FIRST_TOP1 * positionOffset * (1 / FIRST_RATE)));
284 | }
285 |
286 | private void transformRectBgFrom1To2After(float positionOffset) {
287 | /** 快速滑动的时候,可能丢失最后一次绘制,所以需要在这里调重新设置一次,保证变化完成 */
288 | mRectBgCurrentHeight = mPage2RectBgDefaultHeight;
289 | mRectBgCurrentTop = mPage1RectBgDefaultTop + FIRST_TOP1;
290 | /** 第1页,在50%->100%区间偏移 */
291 | /** 矩形背景,在上上偏移30dp后,向下偏移60dp */
292 | mRectBgCurrentTop =
293 | (int) (mPage1RectBgDefaultTop + FIRST_TOP1 + (FIRST_TOP2 * (positionOffset - FIRST_RATE) * 1.0 / (1 - FIRST_RATE)));
294 | }
295 |
296 | private void stepByShowPage2Views(float positionOffset) {
297 | /** 第2页,计算裂变背景图的偏移px,并修改透明度渐变显示 */
298 | float offset =
299 | (mPage1RectBgDefaultWidth + dp2px(15)) * ((positionOffset - FIRST_RATE) * (1 / (1 - FIRST_RATE)));
300 | mPage2Split[0].currentLeft = mPage2Split[0].defaultLeft - offset;
301 | mPage2Split[1].currentLeft = mPage2Split[0].defaultLeft + offset;
302 | /**
303 | * 偏移到50%的时候alpha需要为0,偏移到100%,alpha需要为255,不过此时positionOffset的取值=0.5~1
304 | *
305 | * offset=0.5
306 | * 255 * (0.5 - 0.5) * (1 / (1 - 0.5)))=255 * 0 = 0
307 | *
308 | * offset=0.75
309 | * 255 * (0.75 - 0.5) * (1 / (1 - 0.5)))=255 * 0.5 = 127.5
310 | *
311 | * offset=1
312 | * 255 * (1 - 0.5) * (1 / (1 - 0.5)))=255 * 1 = 255
313 | */
314 | mPage2Split[0].alpha((int) (255 * (positionOffset - FIRST_RATE) * (1 / (1 - FIRST_RATE))));
315 | mPage2Split[1].alpha((int) (255 * (positionOffset - FIRST_RATE) * (1 / (1 - FIRST_RATE))));
316 | }
317 |
318 | private void transformRectBgFrom2To3(float positionOffset) {
319 | /** 快速滑动的时候,可能丢失最后一次绘制,所以需要在这里调重新设置一次,保证变化完成 */
320 | mRectBgCurrentHeight = mPage2RectBgDefaultHeight;
321 | mRectBgCurrentTop = mPage2RectBgDefaultTop;
322 |
323 | /** 矩形背景,宽度缩小15% */
324 | mRectBgCurrentWidth = (int) (mPage2RectBgDefaultWidth * (1 + SECOND_WIDTH * positionOffset));
325 | mRectBgCurrentLeft = getScreenWidth() / 2 - mRectBgCurrentWidth / 2;
326 |
327 | /** 矩形背景,上移20dp */
328 | mRectBgCurrentTop = (int) (mPage2RectBgDefaultTop + (SECOND_TOP * positionOffset));
329 | }
330 |
331 | private void stepByHidePage2Views(float positionOffset, int positionOffsetPixels) {
332 | /** 裂变背景图,跟随滑动,向左偏移至消失 */
333 | mPage2Split[0].currentLeft =
334 | (mPage2Split[0].defaultLeft - mPage1RectBgDefaultWidth - dp2px(15)) - positionOffsetPixels
335 | * (1 / SECOND_RATE);
336 | mPage2Split[1].currentLeft =
337 | (mPage2Split[1].defaultLeft + mPage1RectBgDefaultWidth + dp2px(15)) - positionOffsetPixels
338 | * (1 / SECOND_RATE);
339 | mPage2Split[0].alpha((int) (255 - (255 * positionOffset * (1 / SECOND_RATE))));
340 | mPage2Split[1].alpha((int) (255 - (255 * positionOffset * (1 / SECOND_RATE))));
341 | }
342 |
343 | private boolean isPage4(int currentPageIndex) {
344 | return currentPageIndex == 3;
345 | }
346 |
347 | private boolean fromPage3ToPage4(int position) {
348 | return position == 2;
349 | }
350 |
351 | private boolean fromPage2ToPage3(int position) {
352 | return position == 1;
353 | }
354 |
355 | private boolean fromPage1ToPage2(int position) {
356 | return position == 0;
357 | }
358 |
359 | public void drawBitmap(Canvas canvas, ViewModel viewModel) {
360 | canvas.drawBitmap(viewModel.bitmap, viewModel.currentLeft, viewModel.currentTop, viewModel.paint);
361 | }
362 |
363 | public void drawBitmapMatrix(Canvas canvas, ViewModel viewModel) {
364 | canvas.drawBitmap(viewModel.bitmap, viewModel.matrix, viewModel.paint);
365 | }
366 |
367 | /**
368 | * @desc 根据当前页面,绘制不同的view
369 | * @author listen
370 | */
371 | @Override
372 | protected void onDraw(Canvas canvas) {
373 | super.onDraw(canvas);
374 |
375 | /** 按重叠顺序绘制 */
376 | if (fromPage1ToPage2(mCurrentPageIndex)) {
377 |
378 | /** 绘制第1页,底部背景图 */
379 | drawBitmap(canvas, mPage1BottomBg);
380 |
381 | /** 绘制第2页,裂变背景图 */
382 | drawBitmap(canvas, mPage2Split[0]);
383 | drawBitmap(canvas, mPage2Split[1]);
384 |
385 | /** 绘制白色矩形背景 */
386 | drawWhiteRectBackgroud(canvas);
387 |
388 | } else if (fromPage2ToPage3(mCurrentPageIndex)) {
389 |
390 | /** 绘制第2页,裂变背景图 */
391 | drawBitmap(canvas, mPage2Split[0]);
392 | drawBitmap(canvas, mPage2Split[1]);
393 |
394 | /** 绘制矩形背景 */
395 | drawWhiteRectBackgroud(canvas);
396 |
397 | } else if (fromPage3ToPage4(mCurrentPageIndex)) {
398 | /** 绘制第4页,裂变背景图 */
399 | drawBitmapMatrix(canvas, mPage4Split[0]);
400 | drawBitmapMatrix(canvas, mPage4Split[1]);
401 |
402 | /** 绘制矩形背景 */
403 | drawWhiteRectBackgroud(canvas);
404 |
405 | } else if (isPage4(mCurrentPageIndex)) {
406 |
407 | /** 绘制第4页,裂变背景图 */
408 | drawBitmapMatrix(canvas, mPage4Split[0]);
409 | drawBitmapMatrix(canvas, mPage4Split[1]);
410 |
411 | /** 绘制矩形背景 */
412 | drawWhiteRectBackgroud(canvas);
413 |
414 | }
415 | }
416 |
417 | @NonNull
418 | private RectF drawWhiteRectBackgroud(Canvas canvas) {
419 | RectF rect = new RectF();
420 | rect.left = mRectBgCurrentLeft;
421 | rect.top = mRectBgCurrentTop;
422 | rect.right = rect.left + mRectBgCurrentWidth;
423 | rect.bottom = rect.top + mRectBgCurrentHeight;
424 |
425 | canvas.rotate(mRectBgCurrentDegree, rect.left + mRectBgCurrentWidth / 2, rect.top + mRectBgCurrentHeight / 2);
426 | canvas.drawRoundRect(rect, mRectBgDefaultCorner, mRectBgDefaultCorner, mRectBgPaint);
427 | return rect;
428 | }
429 |
430 | private int padding() {
431 | return dp2px(5);
432 | }
433 |
434 | public int getScreenWidth() {
435 | if (null != getResources() && null != getResources().getDisplayMetrics()) {
436 | return getResources().getDisplayMetrics().widthPixels;
437 | }
438 | return 0;
439 | }
440 |
441 | public int dp2px(float dpValue) {
442 | final float scale = getResources().getDisplayMetrics().density;
443 | return (int) (dpValue * scale + 0.5f);
444 | }
445 |
446 | }
447 |
--------------------------------------------------------------------------------
/app/src/main/java/com/listen/test_mogu_view/viewpager/ViewModel.java:
--------------------------------------------------------------------------------
1 | package com.listen.test_mogu_view.viewpager;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.graphics.BitmapFactory;
6 | import android.graphics.Matrix;
7 | import android.graphics.Paint;
8 |
9 | public class ViewModel {
10 | Bitmap bitmap;
11 | Paint paint;
12 | Matrix matrix;
13 |
14 | /**
15 | * 初始,固定的宽高left,top
16 | */
17 | float defaultWidth;
18 | float defaultHeight;
19 | float defaultLeft;
20 | float defaultTop;
21 |
22 | /**
23 | * 当前的宽高left,top,会根据偏移量进行变化
24 | */
25 | float currentWidth;
26 | float currentHeight;
27 | float currentLeft;
28 | float currentTop;
29 |
30 | public ViewModel(Context context, int resId) {
31 | bitmap = BitmapFactory.decodeResource(context.getResources(), resId);
32 | paint = new Paint();
33 | paint.setAlpha(0);
34 | matrix = new Matrix();
35 | }
36 |
37 | public ViewModel alpha(int alpha) {
38 | paint.setAlpha(alpha);
39 | return this;
40 | }
41 |
42 | public ViewModel width(float width) {
43 | this.currentWidth = this.defaultWidth = width;
44 | return this;
45 | }
46 |
47 | public ViewModel height(float height) {
48 | this.currentHeight = this.defaultHeight = height;
49 | return this;
50 | }
51 |
52 | public ViewModel left(float left) {
53 | this.currentLeft = this.defaultLeft = left;
54 | return this;
55 | }
56 |
57 | public ViewModel top(float top) {
58 | this.currentTop = this.defaultTop = top;
59 | return this;
60 | }
61 |
62 | public ViewModel create() {
63 | // 如果没传高度
64 | if (defaultHeight <= 0) {
65 | if (defaultWidth > 0) {
66 | // 有宽度,则按宽度比例缩放
67 | currentHeight = defaultHeight = (defaultWidth / bitmap.getWidth()) * bitmap.getHeight();
68 | } else {
69 | // 没有宽度,则去图片默认高度
70 | currentHeight = defaultHeight = bitmap.getHeight();
71 | }
72 | }
73 |
74 | // 如果没传宽度
75 | if (defaultWidth <= 0) {
76 | if (defaultHeight > 0) {
77 | // 有宽度,则按宽度比例缩放
78 | currentWidth = defaultWidth = (defaultHeight / bitmap.getHeight()) * bitmap.getWidth();
79 | } else {
80 | // 没有高度,则去图片默认宽度
81 | currentWidth = defaultWidth = bitmap.getWidth();
82 | }
83 | }
84 |
85 | /** 缩放图片尺寸到合适的比例 */
86 | matrix.postScale(currentWidth / bitmap.getWidth(), currentHeight / bitmap.getHeight());
87 | bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
88 | return this;
89 | }
90 |
91 | /**
92 | * @desc 当前宽度变化比例
93 | */
94 | public float widthRate() {
95 | return currentWidth / defaultWidth;
96 | }
97 |
98 | /**
99 | * @desc 当前高度变化比例
100 | */
101 | public float heightRate() {
102 | return currentHeight / defaultHeight;
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/four_bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/listen2code/Test_Mogu_View/8953e9e23ca4c3d28f4d61fd9b3d86f0ca344559/app/src/main/res/drawable-xhdpi/four_bg.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/four_bottom_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/listen2code/Test_Mogu_View/8953e9e23ca4c3d28f4d61fd9b3d86f0ca344559/app/src/main/res/drawable-xhdpi/four_bottom_1.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/four_bottom_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/listen2code/Test_Mogu_View/8953e9e23ca4c3d28f4d61fd9b3d86f0ca344559/app/src/main/res/drawable-xhdpi/four_bottom_2.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/four_bottom_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/listen2code/Test_Mogu_View/8953e9e23ca4c3d28f4d61fd9b3d86f0ca344559/app/src/main/res/drawable-xhdpi/four_bottom_3.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/four_top.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/listen2code/Test_Mogu_View/8953e9e23ca4c3d28f4d61fd9b3d86f0ca344559/app/src/main/res/drawable-xhdpi/four_top.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/one_bottom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/listen2code/Test_Mogu_View/8953e9e23ca4c3d28f4d61fd9b3d86f0ca344559/app/src/main/res/drawable-xhdpi/one_bottom.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/one_bottom_bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/listen2code/Test_Mogu_View/8953e9e23ca4c3d28f4d61fd9b3d86f0ca344559/app/src/main/res/drawable-xhdpi/one_bottom_bg.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/one_top.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/listen2code/Test_Mogu_View/8953e9e23ca4c3d28f4d61fd9b3d86f0ca344559/app/src/main/res/drawable-xhdpi/one_top.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/three_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/listen2code/Test_Mogu_View/8953e9e23ca4c3d28f4d61fd9b3d86f0ca344559/app/src/main/res/drawable-xhdpi/three_1.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/three_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/listen2code/Test_Mogu_View/8953e9e23ca4c3d28f4d61fd9b3d86f0ca344559/app/src/main/res/drawable-xhdpi/three_2.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/three_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/listen2code/Test_Mogu_View/8953e9e23ca4c3d28f4d61fd9b3d86f0ca344559/app/src/main/res/drawable-xhdpi/three_3.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/three_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/listen2code/Test_Mogu_View/8953e9e23ca4c3d28f4d61fd9b3d86f0ca344559/app/src/main/res/drawable-xhdpi/three_4.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/three_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/listen2code/Test_Mogu_View/8953e9e23ca4c3d28f4d61fd9b3d86f0ca344559/app/src/main/res/drawable-xhdpi/three_5.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/three_6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/listen2code/Test_Mogu_View/8953e9e23ca4c3d28f4d61fd9b3d86f0ca344559/app/src/main/res/drawable-xhdpi/three_6.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/two_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/listen2code/Test_Mogu_View/8953e9e23ca4c3d28f4d61fd9b3d86f0ca344559/app/src/main/res/drawable-xhdpi/two_1.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/two_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/listen2code/Test_Mogu_View/8953e9e23ca4c3d28f4d61fd9b3d86f0ca344559/app/src/main/res/drawable-xhdpi/two_2.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/two_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/listen2code/Test_Mogu_View/8953e9e23ca4c3d28f4d61fd9b3d86f0ca344559/app/src/main/res/drawable-xhdpi/two_3.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/two_bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/listen2code/Test_Mogu_View/8953e9e23ca4c3d28f4d61fd9b3d86f0ca344559/app/src/main/res/drawable-xhdpi/two_bg.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/two_bottom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/listen2code/Test_Mogu_View/8953e9e23ca4c3d28f4d61fd9b3d86f0ca344559/app/src/main/res/drawable-xhdpi/two_bottom.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/two_top.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/listen2code/Test_Mogu_View/8953e9e23ca4c3d28f4d61fd9b3d86f0ca344559/app/src/main/res/drawable-xhdpi/two_top.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/select_btn.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | -
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/guide_view_four.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
14 |
21 |
22 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/guide_view_one.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
14 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/guide_view_three.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
14 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/guide_view_two.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
14 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_mogu_viewpager.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
12 |
13 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/listen2code/Test_Mogu_View/8953e9e23ca4c3d28f4d61fd9b3d86f0ca344559/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/listen2code/Test_Mogu_View/8953e9e23ca4c3d28f4d61fd9b3d86f0ca344559/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/listen2code/Test_Mogu_View/8953e9e23ca4c3d28f4d61fd9b3d86f0ca344559/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/listen2code/Test_Mogu_View/8953e9e23ca4c3d28f4d61fd9b3d86f0ca344559/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/listen2code/Test_Mogu_View/8953e9e23ca4c3d28f4d61fd9b3d86f0ca344559/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Test_Mogu_View
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/com/listen/test_mogu_view/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.listen.test_mogu_view;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/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.2.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 |
16 | allprojects {
17 | repositories {
18 | jcenter()
19 | }
20 | }
21 |
22 | task clean(type: Delete) {
23 | delete rootProject.buildDir
24 | }
25 |
--------------------------------------------------------------------------------
/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 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------