一、前言
最近所開發(fā)的項目中需要用到引導頁,在網上找了很久都沒有找到適合的,于是乎就卷起袖子,擼起了代碼,決定寫一個完全自己的引導頁庫。寫完之后頗有成就感,畢竟100%純自己,無添加。寫的過程中遇到不少問題,于是有了這篇筆記。本文仍然會先展示效果。然后分解實現步驟。接著一步步實現。github地址
二、展示效果
圖片的選取有些糙,后續(xù)找到合適的會替換,有合適的也可以推薦
二、步驟分解
1.實現滑動的ViewPager
2.實現底部導航條
3.實現下半部分圖片的變化
4.實現小貓動畫
三、步驟實現
1.ViewPager,這沒有什么好說的,現在的項目中基本都會用到,但我在這糾結了很久,也來來回回做了很多測試。主要糾結是用FragmentPagerAdapter還是PagerAdapter。因為只有一張圖所以使用PagerAdapter是完全可以勝任的。使用PagerAdapter也會比較高效,但最后還是選擇了FragmentPagerAdapter,這里有幾個原因:
1.1如果用一張圖片上下就是一個整體,如果上下任何一個部分有變化整個圖都得變化,這樣就不夠靈活。
1.2找圖太費勁,下半部分是純色,這個是比較好實現的,但要找一個上半部分是圖,下半部分是純色的那就得找設計師了。
使用FragmentPagerAdapter的具體做法是把布局的上半部分用圖片,下半部分透明填充,透明的原因是讓背景能夠顯示出來,這樣ViewPager才可以在最上面。滑動的時候才能觸發(fā)ViewPager的滑動事件。代碼比較簡單,此處省略。
2.底部導航條
剛開始準備使用第三方的庫,這種庫有很多,但后來想了想,既然都寫了,那就一擼到底部。于是就決定自己寫了,其實整個過程也不復雜,只是中間有很多小的細節(jié)只有真正的去擼才能發(fā)現。
首先還是給大家說一下實現的整體思路:整個的導航條就是一個LinearLayout加一個View。它們倆利用shape資源文件設置不同的背景,比較簡單,此處忽略。View的寬短設置為LinearLayout的1/n(導航頁的個數),這里不是太靈活,因為,當個數改變時,還需要計算,實際可以封裝一下,利用屬性去控制,這樣會比較規(guī)范。由于想整個庫一起封裝,所以暫時沒有優(yōu)化。
接下來看一下代碼(導航條代碼單獨抽出)
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) vScroll.getLayoutParams();
float distance = vScroll.getWidth();
int leftDistance = 0;
if (lastOffset < positionOffset && positionOffset > 0) {
//正向
leftDistance = (int) (distance * (position));
lp.leftMargin = leftDistance + (int) (positionOffset * distance);
}
if (lastOffset > positionOffset && positionOffset > 0) {
//反向
leftDistance = (int) (distance * (position + 1));
lp.leftMargin = leftDistance + (int) ((positionOffset - 1) * distance);
}
代碼非常簡單,但里面有幾個需要注意的點:
1.ViewPager從第一頁到第二頁View滑動的距離正常的話應該是自己的寬度所以distance設置為本身的寬度。
2.positionOffset永遠大于等于0,所以必須分正向和逆向,正向和逆向由上次滑動比例和本次滑動比例算出。
3.去除等于0的情況,加上會有抖動,或者與想要的效果不符
4.正向是position 逆向是position+1 .逆向時,如果當前是第二個頁面,稍微往左一些potisition就會變?yōu)?.所以是position+1
5.positionOffset - 1
當運行demo時,可以注意一下打印注釋,順便關注一下上面說到的幾個問題。這樣會比較好理解代碼為什么長這樣。
3.底部圖片處理
底部圖片主要是透明度的變化,沒有太多的難點,注意一些細節(jié)即可下面開一下主要代碼(圖片代碼單獨抽出)
int leftDistance = 0;
if (lastOffset < positionOffset && positionOffset > 0) {
//正向
if (positionOffset < 0.5) {
ivGuideDown.setImageResource(imgResDown[position]);
float alpha = 1 - 2 * positionOffset;
ivGuideDown.setAlpha(alpha < 0.2 ? 0.2f : alpha);
} else {
ivGuideDown.setImageResource(imgResDown[position+1]);
float alpha = (float) (2 * (positionOffset - 0.5));
ivGuideDown.setAlpha(alpha < 0.2 ? 0.2f : alpha);}
}
if (lastOffset > positionOffset && positionOffset > 0) {
//反向
if (positionOffset < 0.5) {
ivGuideDown.setImageResource(imgResDown[position]);
float alpha = 1 - 2 * positionOffset;
(alpha < 0.2 ? 0.2f : alpha);
} else {
ivGuideDown.setImageResource(imgResDown[position+1]);
float alpha = 2 * (positionOffset - 0.5f);
ivGuideDown.setAlpha(alpha < 0.2 ? 0.2f : alpha);
}}
幾個細節(jié)的地方
1.0.5和 2 * positionOffset,0.5是變化的節(jié)點,而透明度是0到1,所以是2 * positionOffset
2.透明度最小 0.2,當0.5或者接近。5時文字為看不到,所以這里設置最小值0.2
3.position和position+1的設定,這里建議大家多看看demo中的打印,效果會更直觀
4、貓的動畫
貓的動畫其實很簡單,就是一個幀動畫。這里是真的不打算說,想了解詳情的可以在github地址 中查看。
四、后記
自此文章已經結束,github地址 的下載地址已經給出,對代碼有修改建議的也可以提出,相互討論。