蘑菇街歡迎頁(yè)
![蘑菇街歡迎頁(yè).gif](https://github.com/listen2code/article/blob/master/%E9%AB%98%E4%BB%BF%E8%98%91%E8%8F%87%E8%A1%97%E6%AC%A2%E8%BF%8E%E9%A1%B5/gif/mogu.gif?raw=true)
高仿效果
![高仿版本.gif](https://github.com/listen2code/article/blob/master/%E9%AB%98%E4%BB%BF%E8%98%91%E8%8F%87%E8%A1%97%E6%AC%A2%E8%BF%8E%E9%A1%B5/gif/my_mogu.gif?raw=true)
這里這里...Demo下載地址
前言
本文將介紹如何對(duì)蘑菇街歡迎頁(yè)效果進(jìn)行分析旦装,拆分券腔,并一步步實(shí)現(xiàn)1個(gè)高仿版本参滴,最重要的設(shè)計(jì)思路包括以下2點(diǎn):
1.ViewPager切換時(shí),通過(guò)offset偏移量動(dòng)態(tài)修改View元素屬性
2.canvas上精細(xì)化的控制旋役纹,移枯冈,縮魄健,透明等view屬性變化,進(jìn)行動(dòng)態(tài)繪制
效果拆解
首先可以把整體效果拆分為靜態(tài)瓦盛,動(dòng)態(tài)2部分绕德。
![整體布局設(shè)計(jì).png](https://github.com/listen2code/article/blob/master/%E9%AB%98%E4%BB%BF%E8%98%91%E8%8F%87%E8%A1%97%E6%AC%A2%E8%BF%8E%E9%A1%B5/screenshot/mogu%E5%B8%83%E5%B1%80.png?raw=true)
-
靜態(tài):1個(gè)支持4個(gè)頁(yè)面的ViewPager,每個(gè)頁(yè)面的展示相對(duì)固定,不會(huì)根據(jù)offset進(jìn)行改變。
- 第1-4頁(yè)的頂部文案
- 第4頁(yè)的開(kāi)始按鈕
-
動(dòng)態(tài):擺放在viewPager上會(huì)變形的自定義View重窟,根據(jù)offset動(dòng)態(tài)調(diào)整需要繪制的元素的寬高顽分,left梯皿,top,透明度等盟萨。
- 第1頁(yè)->第2頁(yè)
- 0%->50%,矩形背景高度增加,先上移梳玫,再下移
- 0%->50%偿荷,模特圖,文案芯侥,下移仰楚,漸變消失
- 50%-100%,左右裂變出2張背景圖捉貌,并左右移開(kāi)
- 50%->100%罢浇,第2頁(yè)色乾,頂部金砍,底部圖,漸變顯示
- 50%->100%笤闯,第2頁(yè)棍厂,3張模特圖逐步放大顯示
- 0%->100%颗味,底部背景圖跟隨向左偏移,并消失
- 第2頁(yè)->第3頁(yè)
- 0%->50%牺弹,矩形背景寬度減少浦马,上移
- 0%->50%,頂部张漂,底部圖晶默,3張模特圖漸變消失
- 0%->50%,2張裂變背景圖跟隨向左偏移航攒,并消失
- 50%->100%磺陡,第3頁(yè),6張模特圖逐步放大,漸變顯示
- 第3頁(yè)->第4頁(yè)
- 0%->50%币他,矩形背景寬度坞靶,高度減少,并逆時(shí)針進(jìn)行旋轉(zhuǎn)
- 0%->50%圆丹,6張模特圖縮小滩愁,漸變消失
- 50%->100%躯喇,左右裂變出2張背景圖辫封,并左右移開(kāi)
- 50%->100%,頂部模特廉丽,文案倦微,漸變顯示
- 50%->100%,底部3長(zhǎng)模特圖逐步放大正压,漸變顯示
- 第1頁(yè)->第2頁(yè)
以上是對(duì)部分實(shí)現(xiàn)細(xì)節(jié)的分析欣福,抽取焦履;本文demo會(huì)全部實(shí)現(xiàn)以上變化效果拓劝。
實(shí)現(xiàn)步驟
1.實(shí)現(xiàn)靜態(tài)的ViewPager
2.根據(jù)offset實(shí)現(xiàn)矩形背景變化
3.根據(jù)offset實(shí)現(xiàn)第1頁(yè)底部背景,第2嘉裤,4頁(yè)裂變背景圖變化
4.根據(jù)offset實(shí)現(xiàn)頁(yè)面切換時(shí)郑临,每個(gè)頁(yè)面圖片元素的隱藏,顯示屑宠,變形等效果
- 實(shí)現(xiàn)靜態(tài)的ViewPager
自定義ViewPager厢洞,每個(gè)頁(yè)面是一個(gè)獨(dú)立layout,可以自由實(shí)現(xiàn)每個(gè)頁(yè)面的頂部文案典奉,和第4個(gè)頁(yè)面的Button
public class MoguViewPager extends RelativeLayout {
private MoguViewPagerAdapter mAdapter;
private ViewPager mViewPager;
private List<View> mViewList = new ArrayList<>();
/** 每個(gè)頁(yè)面都是一個(gè)layout */
private int[] mLayouts = new int[] {R.layout.guide_view_one, R.layout.guide_view_two, R.layout.guide_view_three,
R.layout.guide_view_four};
public MoguViewPager(Context context) {
super(context);
init();
}
public MoguViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
inflate(getContext(), R.layout.layout_mogu_viewpager, this);
mViewPager = (ViewPager) this.findViewById(R.id.viewpager);
{
/** 初始化4個(gè)頁(yè)面 */
for (int i = 0; i < mLayouts.length; i++) {
View view = View.inflate(getContext(), mLayouts[i], null);
mViewList.add(view);
}
}
mAdapter = new MoguViewPagerAdapter(mViewList, getContext());
mViewPager.setAdapter(mAdapter);
}
}
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:clipChildren="false"/>
<!--這里準(zhǔn)備放個(gè)自定義View-->
</RelativeLayout>
第一步完成躺翻,實(shí)現(xiàn)代碼還是比較簡(jiǎn)單的,直接看效果:
![第1版.gif](https://github.com/listen2code/article/blob/master/%E9%AB%98%E4%BB%BF%E8%98%91%E8%8F%87%E8%A1%97%E6%AC%A2%E8%BF%8E%E9%A1%B5/gif/tag1.gif?raw=true)
- 根據(jù)offset實(shí)現(xiàn)矩形背景變化
自定義會(huì)變形的TransforView卫玖,在xml布局中擺放在ViewPager之上
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:clipChildren="false"/>
<com.listen.test_mogu_viewpager.viewpager.TransforView
android:id="@+id/transfor_view" android:layout_width="match_parent"
android:layout_height="450dp"
android:layout_centerInParent="true"/>
</RelativeLayout>
給ViewPager添加addOnPageChangeListener()監(jiān)聽(tīng)公你,在onPageScrolled()的時(shí)候?qū)osition,positionOffset假瞬,positionOffsetPixels傳遞給TransforView陕靠。
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
mTransforView.transfor(position, positionOffset, positionOffsetPixels);
}
});
在TransforView中,首先定義頁(yè)面切換時(shí)變化的參數(shù)笨触,比如第1頁(yè)->第2頁(yè)切換時(shí)懦傍,第1頁(yè)的矩形背景高度放大40%,上移30dp芦劣,下移60dp粗俱,則只需要定義FIRST_HEIGHT=0.4,F(xiàn)IRST_TOP1=-30dp虚吟,F(xiàn)IRST_TOP2 =60dp三個(gè)參數(shù)即可寸认。
/**
* 第1頁(yè)->第2頁(yè)
* 0%->50%签财,矩形背景高度增加40%,先上移30dp偏塞,再下移60dp
*/
public static final float FIRST_HEIGHT = 0.4f;// 第1個(gè)頁(yè)面高度縮放比例唱蒸,正:放大,負(fù):縮小
public final int FIRST_TOP1 = -dp2px(30);// 第1個(gè)頁(yè)面top移動(dòng)距離灸叼,正:下移神汹,負(fù):上移
public final int FIRST_TOP2 = dp2px(60);// 第1個(gè)頁(yè)面top移動(dòng)距離,正:下移古今,負(fù):上移
public static final float FIRST_RATE = 0.5f;// 在偏移50%處屁魏,進(jìn)行下一頁(yè)的顯示
/**
* 第2頁(yè)->第3頁(yè)
* 0%->50%,矩形背景寬度減少15%捉腥,上移20dp
*/
public static final float SECOND_WIDTH = -0.15f;// 第2個(gè)頁(yè)面寬度縮放比例氓拼,正:放大,負(fù):縮小
public final int SECOND_TOP = -dp2px(20);// 第2個(gè)頁(yè)面top移動(dòng)距離比例抵碟,正:下移桃漾,負(fù):上移
public static final float SECOND_RATE = 0.5f;// 在偏移50%處,進(jìn)行下一頁(yè)的顯示
/**
* 第3頁(yè)->第4頁(yè)
* 0%->50%拟逮,矩形背景寬度撬统,高度減少10%,并逆時(shí)針進(jìn)行旋轉(zhuǎn)10度
*/
public static final float THIRD_WIDTH = -0.1f;// 第3個(gè)頁(yè)面寬度縮放比例唱歧,正:放大宪摧,負(fù):縮小
public static final float THIRD_HEIGHT = -0.1f;// 第3個(gè)頁(yè)面高度縮放比例,正:放大颅崩,負(fù):縮小
public static final int THIRD_DEGREE = -10;// 第3個(gè)頁(yè)面角度調(diào)整几于,正:順時(shí)針,負(fù):逆時(shí)針
public static final float THIRD_RATE = 0.5f;// 在偏移50%處沿后,進(jìn)行下一頁(yè)的顯示
/**
* 第1頁(yè)初始化矩形背景的寬沿彭,高,left尖滚,top
*/
private float mPage1RectBgDefaultWidth = dp2px(260);
private float mPage1RectBgDefaultHeight = dp2px(230);
private float mPage1RectBgDefaultLeft = getScreenWidth() / 2 - mPage1RectBgDefaultWidth / 2;//left=屏幕寬度/2-矩形寬度/2
private float mPage1RectBgDefaultTop = dp2px(80);
/**
* 第1頁(yè)->第2頁(yè)
* 在第1頁(yè)的基礎(chǔ)上進(jìn)行變化
* 1.height放大
* 2.top先上移n喉刘,在下移n*2
*/
private float mPage2RectBgDefaultWidth = mPage1RectBgDefaultWidth;
private float mPage2RectBgDefaultHeight = mPage1RectBgDefaultHeight * (1 + FIRST_HEIGHT);// 第2頁(yè)的高度=第一頁(yè)高度*1.4
private float mPage2RectBgDefaultLeft = mPage1RectBgDefaultLeft;
private float mPage2RectBgDefaultTop = mPage1RectBgDefaultTop + FIRST_TOP1 + FIRST_TOP2;//第2頁(yè)的top=第一頁(yè)的top-30dp+60dp
/**
* 第2頁(yè)->第3頁(yè)
* 在第2頁(yè)的基礎(chǔ)上進(jìn)行變化
* 1.寬度縮小
* 2.top上移
*/
private float mPage3RectBgDefaultWidth = mPage2RectBgDefaultWidth * (1 + SECOND_WIDTH);
private float mPage3RectBgDefaultHeight = mPage2RectBgDefaultHeight;
private float mPage3RectBgDefaultLeft = getScreenWidth() / 2 - mPage3RectBgDefaultWidth / 2;//第3頁(yè)的left=屏幕的寬度/2-矩形背景寬度/2
private float mPage3RectBgDefaultTop = mPage2RectBgDefaultTop + SECOND_TOP;
/**
* 第3頁(yè)->第4頁(yè)
* 在第3頁(yè)的基礎(chǔ)上進(jìn)行變化
* 1.寬度縮小
* 2.高度縮小
* 2.逆時(shí)針旋轉(zhuǎn)
*/
private float mPage4RectBgDefaultWidth = mPage3RectBgDefaultWidth * (1 + THIRD_WIDTH);
private float mPage4RectBgDefaultHeight = mPage3RectBgDefaultHeight * (1 + THIRD_HEIGHT);
private float mPage4RectBgDefaultLeft = getScreenWidth() / 2 - mPage4RectBgDefaultWidth / 2;
private float mPage4RectBgDefaultTop = mPage3RectBgDefaultTop;
private float mPage4ModelDefaultWidth = (mPage4RectBgDefaultWidth - padding() * 4) / 3;
TransforView的transfor()方法負(fù)責(zé)接收position,positionOffset漆弄,
positionOffsetPixels睦裳,并根據(jù)position判斷當(dāng)前第幾頁(yè),從而決定要實(shí)現(xiàn)哪些效果撼唾。比如在第1頁(yè)->第2頁(yè)的0%-50區(qū)間時(shí)廉邑,需要將高度放大40%:mRectBgCurrentHeight =(int) (mPage1RectBgDefaultHeight * (1 + FIRST_HEIGHT * positionOffset * (1 / FIRST_RATE)))。mRectBgCurrentHeight是矩形背景當(dāng)前的高度,是個(gè)動(dòng)態(tài)值蛛蒙,mPage1RectBgDefaultHeight是屏幕處于第1頁(yè)時(shí)矩形背景的初始值糙箍,只要基于這個(gè)初始值,根據(jù)positionOffset計(jì)算偏移的比例牵祟,就可以知道當(dāng)前動(dòng)態(tài)的高度值應(yīng)該是多少深夯。
public void transfor(int position, float positionOffset, int positionOffsetPixels) {
mCurrentPageIndex = position;
if (fromPage1ToPage2(position)) {
if (positionOffset < FIRST_RATE) {
/** 第1頁(yè),在0->50%區(qū)間偏移 */
/** 矩形背景诺苹,高度放大40% */
/**
* 偏移到50%的時(shí)候height需要放大40%咕晋,defaultHeight=400,targetHeight=400*1.4=560
*
* offset=0
* 400 * (1 + 0.4 * 0 * (1 / 0.5)) = 400
*
* offset=0.25
* 400 * (1 + 0.4 * 0.25 * (1 / 0.5)) = 400 * 1.2 = 480
*
* offset=0.5
* 400 * (1 + 0.4 * 0.5 * (1 / 0.5)) = 400 * 1.4 = 560
*
*/
mRectBgCurrentHeight =
(int) (mPage1RectBgDefaultHeight * (1 + FIRST_HEIGHT * positionOffset * (1 / FIRST_RATE)));
/** 矩形背景筝尾,向上移動(dòng)30dp */
mRectBgCurrentTop = (int) (mPage1RectBgDefaultTop + (FIRST_TOP1 * positionOffset * (1 / FIRST_RATE)));
} else {
/** 第1頁(yè)捡需,在50%->100%區(qū)間偏移 */
/** 矩形背景,上移30dp后筹淫,向下偏移60dp */
mRectBgCurrentTop =
(int) (mPage1RectBgDefaultTop + FIRST_TOP1 + (FIRST_TOP2 * (positionOffset - FIRST_RATE) * 1.0 / (1 - FIRST_RATE)));
}
} else if (fromPage2ToPage3(position)) {
/** 矩形背景,寬度縮小15% */
mRectBgCurrentWidth = (int) (mPage2RectBgDefaultWidth * (1 + SECOND_WIDTH * positionOffset));
mRectBgCurrentLeft = getScreenWidth() / 2 - mRectBgCurrentWidth / 2;
/** 矩形背景呢撞,上移20dp */
mRectBgCurrentTop = (int) (mPage2RectBgDefaultTop + (SECOND_TOP * positionOffset));
} else if (fromPage3ToPage4(position)) {
/** 背景矩形的寬度损姜,減少10% */
mRectBgCurrentWidth = mPage3RectBgDefaultWidth * (1 + THIRD_WIDTH * positionOffset);
mRectBgCurrentLeft = getScreenWidth() / 2 - mRectBgCurrentWidth / 2;
/** 背景矩形的高度,減少10% */
mRectBgCurrentHeight = mPage3RectBgDefaultHeight * (1 + THIRD_HEIGHT * positionOffset);
/** 逆時(shí)針旋轉(zhuǎn)10度 */
mRectBgCurrentDegree = THIRD_DEGREE * positionOffset;
}
/** 請(qǐng)求重新繪制 */
postInvalidate();
}
最后在onDraw方法中殊霞,調(diào)用canvas.drawRoundRect()將計(jì)算好寬摧阅,高,left绷蹲,top的圓角矩形在繪制在canvas上即可棒卷。
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
RectF rect = new RectF();
rect.left = mRectBgCurrentLeft;
rect.top = mRectBgCurrentTop;
rect.right = rect.left + mRectBgCurrentWidth;
rect.bottom = rect.top + mRectBgCurrentHeight;
canvas.rotate(mRectBgCurrentDegree, rect.left + mRectBgCurrentWidth / 2, rect.top + mRectBgCurrentHeight / 2);
canvas.drawRoundRect(rect, mRectBgDefaultCorner, mRectBgDefaultCorner, mRectBgPaint);
}
第2步:通過(guò)ViewPager的偏移offset,實(shí)現(xiàn)了矩形背景在頁(yè)面間切換時(shí)的變化效果祝钢,如下:
![第2版.gif](https://github.com/listen2code/article/blob/master/%E9%AB%98%E4%BB%BF%E8%98%91%E8%8F%87%E8%A1%97%E6%AC%A2%E8%BF%8E%E9%A1%B5/gif/tag2.gif?raw=true)
- 根據(jù)offset實(shí)現(xiàn)第1頁(yè)底部背景比规,第2,4頁(yè)裂變圖背景圖變化
在TransforView的init()初始化方法中拦英,獲取并設(shè)置圖片的默認(rèn)寬蜒什,高,left疤估,top灾常。這里封裝了1個(gè)ViewModel,里面記錄了在canvas上繪制圖形需要的bitmap铃拇,paint钞瀑,matrix,width慷荔,height雕什,left,top等屬性。在調(diào)用ViewModel.create()的時(shí)候监徘,通過(guò)matrix.postScale()將Bitmap縮放一定比例晋修,以便在矩形背景上進(jìn)行精確的繪制,比如:矩形背景的200凰盔,要在1排展示3張圖墓卦,則每張圖的寬度=(200-矩形左邊距-矩形右邊距-中間2張圖的左右邊距)/3。
public ViewModel create() {
/** 縮放圖片尺寸到合適的比例 */
matrix.postScale(currentWidth / bitmap.getWidth(), currentHeight / bitmap.getHeight());
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
return this;
}
private void init() {
/** 第1頁(yè)户敬,底部背景圖 */
mPage1BottomBg =
new ViewModel(getContext(), R.drawable.one_bottom_bg).alpha(255)
.width(mPage1RectBgDefaultWidth - padding() * 2)
.left(mPage1RectBgDefaultLeft + padding())
// top距離=矩形背景top+height+5dp邊距
.top(mPage1RectBgDefaultTop + mPage1RectBgDefaultHeight + padding())
.create();
/** 第2頁(yè)落剪,裂變背景圖 */
for (int i = 0; i < 2; i++) {
mPage2Split[i] =
new ViewModel(getContext(), R.drawable.two_bg).width(mPage2RectBgDefaultWidth)
.height(mPage2RectBgDefaultHeight)
.left(mPage2RectBgDefaultLeft)
.top(mPage2RectBgDefaultTop)
.create();
}
/** 第4頁(yè),2張裂變背景圖 */
for (int i = 0; i < mPage4Split.length; i++) {
mPage4Split[i] =
new ViewModel(getContext(), R.drawable.four_bg)
.width(mPage4RectBgDefaultWidth)
.height(mPage4RectBgDefaultHeight)
.left(mPage4RectBgDefaultLeft)
.top(mPage4RectBgDefaultTop);
}
}
在transfor()中修改圖片left尿庐,top忠怖,實(shí)現(xiàn)移動(dòng);第1頁(yè)的底部背景圖抄瑟,根據(jù)viewPager向左滑動(dòng)的距離凡泣,跟隨左移,直到消失不可見(jiàn)皮假。在第1頁(yè)滑動(dòng)到50%時(shí)鞋拟,顯示第2頁(yè)裂變背景圖,根據(jù)offset分別左右平移惹资,第4頁(yè)裂變圖原理一致贺纲,只是繪制前需要通過(guò)Matrix.postRotate()將圖進(jìn)行旋轉(zhuǎn)。
private void transfor(int position, float positionOffset, int positionOffsetPixels) {
if (fromPage1ToPage2(position)) {
/** 第1頁(yè)褪测,底部背景圖猴誊,根據(jù)頁(yè)面pian yi偏移offset向左偏移 */
mPage1BottomBg.currentLeft = mPage1BottomBg.defaultLeft - positionOffsetPixels;
if (positionOffset < FIRST_RATE) {
} else {
/** 第2頁(yè),計(jì)算裂變背景圖的偏移px侮措,并修改透明度漸變顯示 */
float offset = (mPage1RectBgDefaultWidth + dp2px(15)) * ((positionOffset - FIRST_RATE) * (1 / (1 - FIRST_RATE)));
mPage2Split[0].currentLeft = mPage2Split[0].defaultLeft - offset;
mPage2Split[1].currentLeft = mPage2Split[0].defaultLeft + offset;
/**
* 偏移到50%的時(shí)候alpha需要為0懈叹,偏移到100%,alpha需要為255萝毛,不過(guò)此時(shí)positionOffset的取值=0.5~1
*
* offset=0.5
* 255 * (0.5 - 0.5) * (1 / (1 - 0.5)))=255 * 0 = 0
*
* offset=0.75
* 255 * (0.75 - 0.5) * (1 / (1 - 0.5)))=255 * 0.5 = 127.5
*
* offset=1
* 255 * (1 - 0.5) * (1 / (1 - 0.5)))=255 * 1 = 255
*/
mPage2Split[0].alpha((int) (255 * (positionOffset - FIRST_RATE) * (1 / (1 - FIRST_RATE))));
mPage2Split[1].alpha((int) (255 * (positionOffset - FIRST_RATE) * (1 / (1 - FIRST_RATE))));
}
} else if (fromPage2ToPage3(position)) {
if (positionOffset < SECOND_RATE) {
}
} else if (fromPage3ToPage4(position)) {
if (positionOffset < THIRD_RATE) {
} else {
/** 顯示第4頁(yè)项阴,裂變背景圖,并向左右平移 */
float offset = (mPage4RectBgDefaultWidth + dp2px(40)) * ((positionOffset - THIRD_RATE) * (1 / (1 - THIRD_RATE)));
for (int i = 0; i < mPage4Split.length; i++) {
mPage4Split[i].matrix.reset();
mPage4Split[i].matrix.postScale(mPage4RectBgDefaultWidth / mPage4Split[i].bitmap.getWidth(), mPage4RectBgDefaultHeight / mPage4Split[i].bitmap.getHeight());
float currentLeft = 0;
if (i == 0) {
// 左移
currentLeft = mPage4RectBgDefaultLeft - offset;
} else if (i == 1) {
// 右移
currentLeft = mPage4RectBgDefaultLeft + offset;
}
// 平移
mPage4Split[i].matrix.postTranslate(currentLeft, mPage4RectBgDefaultTop);
// 旋轉(zhuǎn)角度
mPage4Split[i].matrix.postRotate(THIRD_DEGREE, currentLeft + mPage4RectBgDefaultWidth/2,
mPage4RectBgDefaultTop + mPage4RectBgDefaultHeight/2);
mPage4Split[i].alpha((int) (255 * ((positionOffset - THIRD_RATE) * (1 / (1 - THIRD_RATE)))));
}
}
}
}
效果如下:
![第3版.gif](https://github.com/listen2code/article/blob/master/%E9%AB%98%E4%BB%BF%E8%98%91%E8%8F%87%E8%A1%97%E6%AC%A2%E8%BF%8E%E9%A1%B5/gif/tag3.gif?raw=true)
- 4個(gè)頁(yè)面切換時(shí)笆包,實(shí)現(xiàn)每個(gè)頁(yè)面圖片元素的隱藏环揽,顯示,變形等效果
在transfor()中庵佣,根據(jù)position判斷當(dāng)前頁(yè)數(shù)歉胶,才知道當(dāng)前是從第幾頁(yè)滑動(dòng)到第幾頁(yè),該隱藏巴粪,或顯示哪些view通今。
private void transfor(int position, float positionOffset, int positionOffsetPixels) {
if (fromPage1ToPage2(position)) {
/** 第1頁(yè)粥谬,底部背景圖,根據(jù)頁(yè)面向左偏移 */
mPage1BottomBg.currentLeft = mPage1BottomBg.defaultLeft - positionOffsetPixels;
if (positionOffset < FIRST_RATE) {
/** 第1頁(yè)辫塌,在0->50%區(qū)間偏移 */
/** 矩形背景漏策,高度放大40%,向上移動(dòng)30dp */
transformRectBgFrom1To2Before(positionOffset);
/** 第1頁(yè)臼氨,漸漸隱頂部圖掺喻,底部圖;透明度漸變消失储矩,偏移到50%時(shí)完全消失 */
stepByHidePage1Views(positionOffset);
} else {
/** 第1頁(yè)感耙,在50%->100%區(qū)間偏移 */
/** 矩形背景,上移30dp后持隧,向下偏移60dp */
transformRectBgFrom1To2After(positionOffset);
/** 第2頁(yè)即硼,漸漸顯示頂部,3張模特圖屡拨,底部圖 */
stepByShowPage2Views(positionOffset);
}
} else if (fromPage2ToPage3(position)) {
/** 矩形背景只酥,寬度縮小15%,上移20dp */
transformRectBgFrom2To3(positionOffset);
if (positionOffset < SECOND_RATE) {
/** 第2頁(yè)洁仗,在0->50%區(qū)間偏移层皱,漸漸隱藏頂部,中間赠潦,底部,裂變背景圖 */
stepByHidePage2Views(positionOffset, positionOffsetPixels);
} else {
/** 第2頁(yè)草冈,在50->100%區(qū)間偏移她奥,漸漸顯示第3頁(yè),6張模特圖 */
stepByShowPage3Views(positionOffset);
}
} else if (fromPage3ToPage4(position)) {
/** 背景矩形的寬度怎棱,高度減少10%哩俭,逆時(shí)針旋轉(zhuǎn)10度 */
transformRectBgFrom3To4(positionOffset);
if (positionOffset < THIRD_RATE) {
/** 漸漸縮放,隱藏第3頁(yè)拳恋,6張模特圖 */
stepByHidePage3Views(positionOffset);
} else {
/** 漸漸顯示第4頁(yè)凡资,頂部圖,底部3張模特圖谬运,分裂背景圖 */
stepByShowPage4Views(positionOffset);
}
}
}
第1頁(yè)->第2頁(yè)隙赁,偏移區(qū)間0%-50%時(shí)
- 矩形背景,高度放大40%梆暖,向上移動(dòng)30dp
- 漸漸隱藏第1頁(yè)頂部伞访,底部圖;透明度漸變消失轰驳,偏移到50%時(shí)完全消失
private void transformRectBgFrom1To2Before(float positionOffset) {
/** 矩形背景厚掷,高度放大40% */
/**
* 偏移到50%的時(shí)候height需要放大40%弟灼,defaultHeight=400,targetHeight=400*1.4=560
*
* offset=0
* 400 * (1 + 0.4 * 0 * (1 / 0.5)) = 400
*
* offset=0.25
* 400 * (1 + 0.4 * 0.25 * (1 / 0.5)) = 400 * 1.2 = 480
*
* offset=0.5
* 400 * (1 + 0.4 * 0.5 * (1 / 0.5)) = 400 * 1.4 = 560
*
*/
mRectBgCurrentHeight =
(int) (mPage1RectBgDefaultHeight * (1 + FIRST_HEIGHT * positionOffset * (1 / FIRST_RATE)));
/** 矩形背景冒黑,向上移動(dòng)30dp */
mRectBgCurrentTop = (int) (mPage1RectBgDefaultTop + (FIRST_TOP1 * positionOffset * (1 / FIRST_RATE)));
private void stepByHidePage1Views(float positionOffset) {
/**
* 偏移到50%的時(shí)候alpha需要為0田绑,view不可見(jiàn)
*
* offset=0
* 255-(255*0.0*(1/0.5)) = 0
*
* offset=0.25
* 255-(255*0.25*(1/0.5)) = 127
*
* offset=0.5
* 255-(255*0.5*(1/0.5)) = 255
*/
mPage1Top.alpha((int) (255 - (255 * positionOffset * (1 / FIRST_RATE))));
mPage1Bottom.alpha((int) (255 - (255 * positionOffset * (1 / FIRST_RATE))));
/** 第1頁(yè),頂部圖向下移動(dòng) */
mPage1Top.currentTop = mPage1Top.defaultTop + (FIRST_TOP2 + FIRST_TOP1) * positionOffset * (1 / FIRST_RATE);
/** 第1頁(yè)抡爹,底部圖跟隨頂部圖向下移動(dòng) */
mPage1Bottom.currentTop = mPage1Top.currentTop + mPage1Top.defaultHeight + padding();
}
第1頁(yè)->第2頁(yè)掩驱,偏移區(qū)間50%-100%時(shí)
- 矩形背景,向下移動(dòng)60dp
- 顯示第2頁(yè)裂變背景圖豁延,并左右平移
- 逐漸顯示第2頁(yè)昙篙,頂部,底部圖诱咏,3張模特圖
private void transformRectBgFrom1To2After(float positionOffset) {
/** 快速滑動(dòng)的時(shí)候苔可,可能丟失最后一次繪制,所以需要在這里調(diào)重新設(shè)置一次袋狞,保證變化完成 */
mRectBgCurrentHeight = mPage2RectBgDefaultHeight;
mRectBgCurrentTop = mPage1RectBgDefaultTop + FIRST_TOP1;
/** 第1頁(yè)焚辅,在50%->100%區(qū)間偏移 */
/** 矩形背景,在上上偏移30dp后苟鸯,向下偏移60dp */
mRectBgCurrentTop =
(int) (mPage1RectBgDefaultTop + FIRST_TOP1 + (FIRST_TOP2 * (positionOffset - FIRST_RATE) * 1.0 / (1 - FIRST_RATE)));
}
private void stepByShowPage2Views(float positionOffset) {
/** 第2頁(yè)同蜻,頂部圖,跟隨矩形背景下移 */
mPage2Top.currentTop = mRectBgCurrentTop + padding();
/** 第2頁(yè)早处,底部圖湾蔓,跟隨矩形背景下移 */
mPage2Bottom.currentTop = mPage2Center[0].currentTop + mPage2Center[0].defaultHeight + padding();
/** 第2頁(yè),計(jì)算裂變背景圖的偏移px砌梆,并修改透明度漸變顯示 */
float offset =
(mPage1RectBgDefaultWidth + dp2px(15)) * ((positionOffset - FIRST_RATE) * (1 / (1 - FIRST_RATE)));
mPage2Split[0].currentLeft = mPage2Split[0].defaultLeft - offset;
mPage2Split[1].currentLeft = mPage2Split[0].defaultLeft + offset;
/**
* 偏移到50%的時(shí)候alpha需要為0默责,偏移到100%,alpha需要為255咸包,不過(guò)此時(shí)positionOffset的取值=0.5~1
*
* offset=0.5
* 255 * (0.5 - 0.5) * (1 / (1 - 0.5)))=255 * 0 = 0
*
* offset=0.75
* 255 * (0.75 - 0.5) * (1 / (1 - 0.5)))=255 * 0.5 = 127.5
*
* offset=1
* 255 * (1 - 0.5) * (1 / (1 - 0.5)))=255 * 1 = 255
*/
mPage2Split[0].alpha((int) (255 * (positionOffset - FIRST_RATE) * (1 / (1 - FIRST_RATE))));
mPage2Split[1].alpha((int) (255 * (positionOffset - FIRST_RATE) * (1 / (1 - FIRST_RATE))));
/** 第2頁(yè)桃序,頂部,底部圖烂瘫,透明度漸變顯示媒熊,偏移量達(dá)到100%,完成顯示 */
mPage2Top.alpha((int) (255 * (positionOffset - FIRST_RATE) * (1 / (1 - FIRST_RATE))));
mPage2Bottom.alpha((int) (255 * (positionOffset - FIRST_RATE) * (1 / (1 - FIRST_RATE))));
/** 第2頁(yè)坟比,顯示中間3張模特圖 */
for (int i = 0; i < mPage2Center.length; i++) {
if (i == 0) {
/** 第2頁(yè)芦鳍,顯示第1張模特圖 */
mPage2Center[i].currentWidth =
mPage2Center[i].defaultWidth * (positionOffset - FIRST_RATE) * 1 / (1 - FIRST_RATE);
mPage2Center[i].currentHeight =
mPage2Center[i].defaultHeight * (positionOffset - FIRST_RATE) * 1 / (1 - FIRST_RATE);
mPage2Center[i].alpha((int) (255 * (positionOffset - FIRST_RATE) * (1 / (1 - FIRST_RATE))));
mPage2Center[i].currentTop = mPage2Top.currentTop + mPage2Top.currentHeight + padding();
} else {
/** 第2,3張模特圖温算,在前1張顯示到一半時(shí)才顯示 */
if (mPage2Center[i - 1].currentWidth >= mPage2Center[i - 1].defaultWidth / 2) {
float rate = mPage2Center[i - 1].widthRate() - 0.5f;
mPage2Center[i].currentWidth = mPage2Center[i].defaultWidth * (rate * 2);
mPage2Center[i].currentHeight = mPage2Center[i].defaultHeight * (rate * 2);
/** 第2怜校,3張模特圖,需要根據(jù)第1張圖計(jì)算left */
mPage2Center[i].currentLeft =
mPage2Center[0].currentLeft + mPage2Center[0].currentWidth + padding();
mPage2Center[i].currentTop = mPage2Top.currentTop + mPage2Top.currentHeight + padding();
if (i == 2) {
/** 第3張模特圖注竿,根據(jù)第2張圖計(jì)算top */
mPage2Center[i].currentTop =
mPage2Center[1].currentTop + mPage2Center[1].currentHeight + padding();
}
mPage2Center[i].alpha((int) (255 * (positionOffset * rate * 2)));
} else {
mPage2Center[i].alpha(0);
}
}
}
}
第2頁(yè)->第3頁(yè)茄茁,偏移區(qū)間0%-100%時(shí)
- 矩形背景魂贬,寬度縮小15%
- 矩形背景,上移20dp
private void transformRectBgFrom2To3(float positionOffset) {
/** 快速滑動(dòng)的時(shí)候裙顽,可能丟失最后一次繪制付燥,所以需要在這里調(diào)重新設(shè)置一次,保證變化完成 */
mRectBgCurrentHeight = mPage2RectBgDefaultHeight;
mRectBgCurrentTop = mPage2RectBgDefaultTop;
/** 矩形背景愈犹,寬度縮小15% */
mRectBgCurrentWidth = (int) (mPage2RectBgDefaultWidth * (1 + SECOND_WIDTH * positionOffset));
mRectBgCurrentLeft = getScreenWidth() / 2 - mRectBgCurrentWidth / 2;
/** 矩形背景键科,上移20dp */
mRectBgCurrentTop = (int) (mPage2RectBgDefaultTop + (SECOND_TOP * positionOffset));
}
第2頁(yè)->第3頁(yè),偏移區(qū)間0%-50%時(shí)
- 裂變背景圖跟隨滑動(dòng)漩怎,向左偏移至消失
- 漸漸減少透明度勋颖,隱藏第2頁(yè)的頂部圖,3張模特圖勋锤,底部圖
private void stepByHidePage2Views(float positionOffset, int positionOffsetPixels) {
/** 裂變背景圖饭玲,跟隨滑動(dòng),向左偏移至消失 */
mPage2Split[0].currentLeft =
(mPage2Split[0].defaultLeft - mPage1RectBgDefaultWidth - dp2px(15)) - positionOffsetPixels
* (1 / SECOND_RATE);
mPage2Split[1].currentLeft =
(mPage2Split[1].defaultLeft + mPage1RectBgDefaultWidth + dp2px(15)) - positionOffsetPixels
* (1 / SECOND_RATE);
mPage2Split[0].alpha((int) (255 - (255 * positionOffset * (1 / SECOND_RATE))));
mPage2Split[1].alpha((int) (255 - (255 * positionOffset * (1 / SECOND_RATE))));
/** 頂部圖叁执,3張模特圖茄厘,底部圖,跟隨矩形背景上移 */
mPage2Top.currentTop = mRectBgCurrentTop + padding();
mPage2Center[0].currentTop = mPage2Top.currentTop + mPage2Top.currentHeight + padding();
mPage2Center[1].currentTop = mPage2Center[0].currentTop;
mPage2Center[2].currentTop = mPage2Center[1].currentTop + mPage2Center[1].currentHeight;
mPage2Bottom.currentTop = mPage2Center[0].currentTop + mPage2Center[0].currentHeight + padding();
/** 漸漸減少透明度谈宛,隱藏第2頁(yè)的頂部圖次哈,3張模特圖,底部圖 */
mPage2Top.alpha((int) (255 - (255 * positionOffset * (1 / SECOND_RATE))));
mPage2Bottom.alpha((int) (255 - (255 * positionOffset * (1 / SECOND_RATE))));
for (ViewModel viewModel : mPage2Center) {
viewModel.alpha((int) (255 - (255 * positionOffset * (1 / SECOND_RATE))));
}
/** 因?yàn)榫匦伪尘白冋诉郝迹詽u漸減少第2頁(yè)頂部圖窑滞,底部圖的寬度,實(shí)現(xiàn)跟隨矩形背景寬度變化 */
mPage2Top.currentWidth = mRectBgCurrentWidth - padding() * 2;
mPage2Top.currentLeft = mRectBgCurrentLeft + padding();
mPage2Bottom.currentWidth = mRectBgCurrentWidth - padding() * 2;
mPage2Bottom.currentLeft = mRectBgCurrentLeft + padding();
mPage2Bottom.currentLeft = mRectBgCurrentLeft + padding();
/** 因?yàn)榫匦伪尘白冋嘶煮荩詽u漸減少第2葛假,3張模特圖的寬高,left和top滋恬,實(shí)現(xiàn)跟隨矩形背景寬度變化 */
mPage2Center[0].currentLeft = mRectBgCurrentLeft + padding();
mPage2Center[1].currentWidth = mRectBgCurrentWidth - padding() * 3 - mPage2Center[0].defaultWidth;
mPage2Center[1].currentHeight = mPage2Center[1].currentWidth;
mPage2Center[1].currentLeft = mPage2Center[0].currentLeft + mPage2Center[0].defaultWidth + padding();
mPage2Center[2].currentWidth = mRectBgCurrentWidth - padding() * 3 - mPage2Center[0].defaultWidth;
mPage2Center[2].currentHeight = mPage2Center[2].currentWidth;
mPage2Center[2].currentLeft = mPage2Center[0].currentLeft + mPage2Center[0].defaultWidth + padding();
mPage2Center[2].currentTop = mPage2Center[1].currentTop + mPage2Center[1].currentHeight + padding();
}
第2頁(yè)->第3頁(yè),偏移區(qū)間50%-100%時(shí)
- 依次顯示第3頁(yè)抱究,6張模特圖
private void stepByShowPage3Views(float positionOffset) {
/** 第2頁(yè)恢氯,在50->100%區(qū)間偏移,顯示第3頁(yè)鼓寺,6張模特圖 */
for (int i = 0; i < mPage3Model.length; i++) {
if (i == 0) {
/** 第1張模特圖先顯示 */
if (mPage3Model[i].paint.getAlpha() < 255) {
mPage3Model[i].alpha((int) (255 * (positionOffset - SECOND_RATE) * (1 / (1 - SECOND_RATE))));
}
} else {
/** 其他模特圖在前1張顯示50%透明度的時(shí)候再依次展示 */
if (mPage3Model[i - 1].paint.getAlpha() >= 255 / 2) {
float rate = mPage3Model[i - 1].paint.getAlpha() / 255.0f - 0.5f;
mPage3Model[i].alpha((int) (255 * (rate * 2)));
} else {
mPage3Model[i].alpha(0);
}
}
/** 6張模特圖勋拟,跟隨矩形背景上移 */
if (i < mPage3ModelResources.length / 2) {
/** 第1排,3張模特圖的top計(jì)算 */
mPage3Model[i].currentTop = mRectBgCurrentTop + padding();
} else {
/** 第1排妈候,3張模特圖的top敢靡,需要加上第一排的height */
mPage3Model[i].currentTop = mRectBgCurrentTop + mPage3ModelDefaultHeight + padding() * 2;
}
}
}
第3頁(yè)->第4頁(yè),偏移區(qū)間0%-100%時(shí)
- 矩形背景苦银,寬度縮小10%
- 矩形背景啸胧,高度縮小10%
- 矩形背景赶站,逆時(shí)針旋轉(zhuǎn)10度
private void transformRectBgFrom3To4(float positionOffset) {
/** 快速滑動(dòng)的時(shí)候,可能丟失最后一次繪制纺念,所以需要在這里調(diào)重新設(shè)置一次贝椿,保證變化完成 */
mRectBgCurrentWidth = mPage3RectBgDefaultWidth;
mRectBgCurrentTop = mPage3RectBgDefaultTop;
/** 調(diào)整第4頁(yè),背景矩形的寬高和角度 */
/** 背景矩形的寬度陷谱,在第3頁(yè)調(diào)整寬度的基礎(chǔ)上進(jìn)行縮小 */
mRectBgCurrentWidth = mPage3RectBgDefaultWidth * (1 + THIRD_WIDTH * positionOffset);
mRectBgCurrentLeft = getScreenWidth() / 2 - mRectBgCurrentWidth / 2;
/** 背景矩形的高度烙博,在第2頁(yè)調(diào)整高度的基礎(chǔ)上進(jìn)行縮小 */
mRectBgCurrentHeight = mPage3RectBgDefaultHeight * (1 + THIRD_HEIGHT * positionOffset);
/** 背景矩形逆時(shí)針旋轉(zhuǎn) */
mRectBgCurrentDegree = THIRD_DEGREE * positionOffset;
}
第3頁(yè)->第4頁(yè),偏移區(qū)間0%-50%時(shí)
- 漸漸縮放烟逊,隱藏6張模特圖
private void stepByHidePage3Views(float positionOffset) {
/** 隱藏第3頁(yè)6張模特圖 */
/** 從第1排渣窜,第3-1張開(kāi)始,依次縮放 */
for (int i = mPage3ModelResources.length / 2 - 1; i >= 0; i--) {
if (i == mPage3ModelResources.length / 2 - 1) {
/** 如果是第1排宪躯,第3張乔宿,則開(kāi)始縮放 */
mPage3Model[i].currentHeight =
mPage3Model[i].defaultHeight * (1 - positionOffset * (1 / (1 - THIRD_RATE)));
mPage3Model[i].currentWidth =
mPage3Model[i].defaultWidth * (1 - positionOffset * (1 / (1 - THIRD_RATE)));
} else {
/** 如果是第1排,第1/2張眷唉,則判斷后1張縮放到一半的時(shí)候開(kāi)始自己的縮放 */
if (mPage3Model[i + 1].currentHeight <= mPage3Model[i + 1].defaultHeight / 2) {
mPage3Model[i].currentHeight = mPage3Model[i].defaultHeight * mPage3Model[i + 1].heightRate() * 2;
mPage3Model[i].currentWidth = mPage3Model[i].defaultWidth * mPage3Model[i + 1].heightRate() * 2;
} else {
mPage3Model[i].currentHeight = mPage3Model[i].defaultHeight;
mPage3Model[i].currentWidth = mPage3Model[i].defaultWidth;
}
}
/** 跳轉(zhuǎn)left予颤,top,實(shí)現(xiàn)居中縮放 */
mPage3Model[i].currentLeft =
mPage3Model[i].defaultLeft + mPage3Model[i].defaultWidth / 2 - mPage3Model[i].currentWidth / 2;
mPage3Model[i].currentTop =
mPage3Model[i].defaultTop + mPage3Model[i].defaultHeight / 2 - mPage3Model[i].currentHeight / 2;
}
/** 從第1排冬阳,第4-6張開(kāi)始蛤虐,依次縮放 */
for (int i = mPage3ModelResources.length / 2; i < mPage3ModelResources.length; i++) {
if (i == mPage3ModelResources.length / 2) {
/** 如果是第2排,第1張肝陪,則開(kāi)始縮放 */
mPage3Model[i].currentHeight =
mPage3Model[i].defaultHeight * (1 - positionOffset * (1 / (1 - THIRD_RATE)));
mPage3Model[i].currentWidth =
mPage3Model[i].defaultWidth * (1 - positionOffset * (1 / (1 - THIRD_RATE)));
} else {
/** 如果是第2排驳庭,第5/6張,則判斷前1張縮放到一半的時(shí)候開(kāi)始自己的縮放 */
if (mPage3Model[i - 1].currentHeight <= mPage3Model[i - 1].defaultHeight / 2) {
mPage3Model[i].currentHeight = mPage3Model[i].defaultHeight * mPage3Model[i - 1].heightRate() * 2;
mPage3Model[i].currentWidth = mPage3Model[i].defaultWidth * mPage3Model[i - 1].heightRate() * 2;
} else {
mPage3Model[i].currentHeight = mPage3Model[i].defaultHeight;
mPage3Model[i].currentWidth = mPage3Model[i].defaultWidth;
}
}
/** 跳轉(zhuǎn)left氯窍,top饲常,實(shí)現(xiàn)居中縮放 */
mPage3Model[i].currentLeft =
mPage3Model[i].defaultLeft + mPage3Model[i].defaultWidth / 2 - mPage3Model[i].currentWidth / 2;
mPage3Model[i].currentTop =
mPage3Model[i].defaultTop + mPage3Model[i].defaultHeight / 2 - mPage3Model[i].currentHeight / 2;
}
}
第3頁(yè)->第4頁(yè),偏移區(qū)間50%-100%時(shí)
- 漸漸顯示頂部圖狼讨,底部3張模特圖
- 顯示第4頁(yè)裂變背景圖贝淤,并左右平移
private void stepByShowPage4Views(float positionOffset) {
/** 顯示第4頁(yè),裂變背景圖政供,并向左右平移 */
float offset = (mPage4RectBgDefaultWidth + dp2px(40)) * ((positionOffset - THIRD_RATE) * (1 / (1 - THIRD_RATE)));
for (int i = 0; i < mPage4Split.length; i++) {
mPage4Split[i].matrix.reset();
mPage4Split[i].matrix.postScale(mPage4RectBgDefaultWidth / mPage4Split[i].bitmap.getWidth(), mPage4RectBgDefaultHeight / mPage4Split[i].bitmap.getHeight());
float currentLeft = 0;
if (i == 0) {
// 左移
currentLeft = mPage4RectBgDefaultLeft - offset;
} else if (i == 1) {
// 右移
currentLeft = mPage4RectBgDefaultLeft + offset;
}
// 平移
mPage4Split[i].matrix.postTranslate(currentLeft, mPage4RectBgDefaultTop);
// 旋轉(zhuǎn)角度
mPage4Split[i].matrix.postRotate(THIRD_DEGREE, currentLeft + mPage4RectBgDefaultWidth/2,
mPage4RectBgDefaultTop + mPage4RectBgDefaultHeight/2);
mPage4Split[i].alpha((int) (255 * ((positionOffset - THIRD_RATE) * (1 / (1 - THIRD_RATE)))));
}
/** 顯示第4頁(yè)播聪,頂部模特圖 */
mPage4Top.alpha((int) (255 * ((positionOffset - THIRD_RATE) * (1 / (1 - THIRD_RATE)))));
/** 顯示第4頁(yè),底部3張模特圖 */
for (int i = 0; i < mPage4Model.length; i++) {
if (i == 0) {
mPage4Model[i].currentWidth =
mPage4Model[i].defaultWidth * ((positionOffset - THIRD_RATE) * (1 / (1 - THIRD_RATE)));
mPage4Model[i].currentHeight =
mPage4Model[i].defaultHeight * ((positionOffset - THIRD_RATE) * (1 / (1 - THIRD_RATE)));
mPage4Model[i].alpha((int) (255 * (positionOffset - THIRD_RATE) * (1 / (1 - THIRD_RATE))));
} else {
if (mPage4Model[i - 1].currentWidth >= mPage4ModelDefaultWidth / 2) {
mPage4Model[i].currentWidth =
mPage4Model[i].defaultWidth * ((mPage4Model[i - 1].widthRate() - 0.5f) * 2);
mPage4Model[i].currentHeight =
mPage4Model[i].defaultHeight * ((mPage4Model[i - 1].widthRate() - 0.5f) * 2);
mPage4Model[i].currentLeft =
mPage4Model[i - 1].currentLeft + mPage4Model[i - 1].currentWidth + padding();
mPage4Model[i].alpha((int) (255 * (mPage4Model[i - 1].widthRate() - 0.5f) * 2));
}
}
}
}
最后在onDraw()布隔,將計(jì)算好偏移值的view都繪制出來(lái)离陶。
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
/** 按重疊順序繪制 */
if (fromPage1ToPage2(mCurrentPageIndex)) {
/** 繪制第1頁(yè),底部背景圖 */
drawBitmap(canvas, mPage1BottomBg);
/** 繪制第2頁(yè)衅檀,裂變背景圖 */
drawBitmap(canvas, mPage2Split[0]);
drawBitmap(canvas, mPage2Split[1]);
/** 繪制白色矩形背景 */
drawWhiteRectBackgroud(canvas);
drawPage1InCanvas(canvas);
drawPage2InCanvas(canvas);
} else if (fromPage2ToPage3(mCurrentPageIndex)) {
/** 繪制第2頁(yè)招刨,裂變背景圖 */
drawBitmap(canvas, mPage2Split[0]);
drawBitmap(canvas, mPage2Split[1]);
/** 繪制矩形背景 */
drawWhiteRectBackgroud(canvas);
drawPage2InCanvas(canvas);
drawPage3InCanvas(canvas);
} else if (fromPage3ToPage4(mCurrentPageIndex)) {
/** 繪制第4頁(yè),裂變背景圖 */
drawBitmapMatrix(canvas, mPage4Split[0]);
drawBitmapMatrix(canvas, mPage4Split[1]);
/** 繪制矩形背景 */
drawWhiteRectBackgroud(canvas);
drawPage3InCanvas(canvas);
drawPage4InCanvas(canvas);
} else if (isPage4(mCurrentPageIndex)) {
/** 繪制第4頁(yè)哀军,裂變背景圖 */
drawBitmapMatrix(canvas, mPage4Split[0]);
drawBitmapMatrix(canvas, mPage4Split[1]);
/** 繪制矩形背景 */
drawWhiteRectBackgroud(canvas);
drawPage4InCanvas(canvas);
}
}
最終效果:
![高仿版本.gif](https://github.com/listen2code/article/blob/master/%E9%AB%98%E4%BB%BF%E8%98%91%E8%8F%87%E8%A1%97%E6%AC%A2%E8%BF%8E%E9%A1%B5/gif/my_mogu.gif?raw=true)
目前還有一些細(xì)節(jié)的效果沉眶,以及適配打却,性能調(diào)優(yōu)還沒(méi)實(shí)現(xiàn)。雖然原理不難沦寂,不過(guò)要真正完整的實(shí)現(xiàn)以上效果学密,也算嘔心瀝血吧!難點(diǎn)就在于如何精細(xì)化的控制每個(gè)view的屬性传藏,因?yàn)轫?yè)面中每個(gè)圖片的位置腻暮,大小都是在參照其他view的基礎(chǔ)上進(jìn)行計(jì)算后得出的。現(xiàn)在市場(chǎng)上很多APP的歡迎頁(yè)都有類(lèi)似比較動(dòng)態(tài)的效果毯侦,原理就是ViewPager+Canvas繪制哭靖,掌握了本文的demo,其他實(shí)現(xiàn)原理應(yīng)該是一樣樣的侈离。感興趣的朋友可以Github上下載源碼查看试幽, 注釋還算清晰,有什么問(wèn)題頁(yè)歡迎提出卦碾,如果本文稍微對(duì)您有點(diǎn)啟示的話(huà)還請(qǐng)點(diǎn)個(gè)“喜歡”铺坞,謝謝了