一、前言
最近所開(kāi)發(fā)的項(xiàng)目中需要用到引導(dǎo)頁(yè)谎懦,在網(wǎng)上找了很久都沒(méi)有找到適合的肚豺,于是乎就卷起袖子,擼起了代碼界拦,決定寫(xiě)一個(gè)完全自己的引導(dǎo)頁(yè)庫(kù)吸申。寫(xiě)完之后頗有成就感,畢竟100%純自己,無(wú)添加截碴。寫(xiě)的過(guò)程中遇到不少問(wèn)題梳侨,于是有了這篇筆記。本文仍然會(huì)先展示效果隐岛。然后分解實(shí)現(xiàn)步驟猫妙。接著一步步實(shí)現(xiàn)瓷翻。github地址
二聚凹、展示效果
圖片的選取有些糙,后續(xù)找到合適的會(huì)替換齐帚,有合適的也可以推薦
二妒牙、步驟分解
1.實(shí)現(xiàn)滑動(dòng)的ViewPager
2.實(shí)現(xiàn)底部導(dǎo)航條
3.實(shí)現(xiàn)下半部分圖片的變化
4.實(shí)現(xiàn)小貓動(dòng)畫(huà)
三、步驟實(shí)現(xiàn)
1.ViewPager,這沒(méi)有什么好說(shuō)的对妄,現(xiàn)在的項(xiàng)目中基本都會(huì)用到湘今,但我在這糾結(jié)了很久,也來(lái)來(lái)回回做了很多測(cè)試剪菱。主要糾結(jié)是用FragmentPagerAdapter還是PagerAdapter摩瞎。因?yàn)橹挥幸粡垐D所以使用PagerAdapter是完全可以勝任的。使用PagerAdapter也會(huì)比較高效孝常,但最后還是選擇了FragmentPagerAdapter旗们,這里有幾個(gè)原因:
1.1如果用一張圖片上下就是一個(gè)整體,如果上下任何一個(gè)部分有變化整個(gè)圖都得變化构灸,這樣就不夠靈活上渴。
1.2找圖太費(fèi)勁,下半部分是純色喜颁,這個(gè)是比較好實(shí)現(xiàn)的稠氮,但要找一個(gè)上半部分是圖,下半部分是純色的那就得找設(shè)計(jì)師了半开。
使用FragmentPagerAdapter的具體做法是把布局的上半部分用圖片隔披,下半部分透明填充,透明的原因是讓背景能夠顯示出來(lái)寂拆,這樣ViewPager才可以在最上面奢米。滑動(dòng)的時(shí)候才能觸發(fā)ViewPager的滑動(dòng)事件漓库。代碼比較簡(jiǎn)單纤子,此處省略。
2.底部導(dǎo)航條
剛開(kāi)始準(zhǔn)備使用第三方的庫(kù)每庆,這種庫(kù)有很多值纱,但后來(lái)想了想,既然都寫(xiě)了,那就一擼到底部怠蹂。于是就決定自己寫(xiě)了善延,其實(shí)整個(gè)過(guò)程也不復(fù)雜,只是中間有很多小的細(xì)節(jié)只有真正的去擼才能發(fā)現(xiàn)城侧。
首先還是給大家說(shuō)一下實(shí)現(xiàn)的整體思路:整個(gè)的導(dǎo)航條就是一個(gè)LinearLayout加一個(gè)View易遣。它們倆利用shape資源文件設(shè)置不同的背景,比較簡(jiǎn)單嫌佑,此處忽略豆茫。View的寬短設(shè)置為L(zhǎng)inearLayout的1/n(導(dǎo)航頁(yè)的個(gè)數(shù)),這里不是太靈活,因?yàn)槲菀。?dāng)個(gè)數(shù)改變時(shí)揩魂,還需要計(jì)算,實(shí)際可以封裝一下炮温,利用屬性去控制火脉,這樣會(huì)比較規(guī)范。由于想整個(gè)庫(kù)一起封裝柒啤,所以暫時(shí)沒(méi)有優(yōu)化倦挂。
接下來(lái)看一下代碼(導(dǎo)航條代碼單獨(dú)抽出)
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);
}
代碼非常簡(jiǎn)單,但里面有幾個(gè)需要注意的點(diǎn):
1.ViewPager從第一頁(yè)到第二頁(yè)View滑動(dòng)的距離正常的話應(yīng)該是自己的寬度所以distance設(shè)置為本身的寬度担巩。
2.positionOffset永遠(yuǎn)大于等于0方援,所以必須分正向和逆向,正向和逆向由上次滑動(dòng)比例和本次滑動(dòng)比例算出。
3.去除等于0的情況兵睛,加上會(huì)有抖動(dòng)肯骇,或者與想要的效果不符
4.正向是position 逆向是position+1 .逆向時(shí),如果當(dāng)前是第二個(gè)頁(yè)面祖很,稍微往左一些potisition就會(huì)變?yōu)?.所以是position+1
5.positionOffset - 1
當(dāng)運(yùn)行demo時(shí)笛丙,可以注意一下打印注釋,順便關(guān)注一下上面說(shuō)到的幾個(gè)問(wèn)題假颇。這樣會(huì)比較好理解代碼為什么長(zhǎng)這樣胚鸯。
3.底部圖片處理
底部圖片主要是透明度的變化,沒(méi)有太多的難點(diǎn)笨鸡,注意一些細(xì)節(jié)即可下面開(kāi)一下主要代碼(圖片代碼單獨(dú)抽出)
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);
}}
幾個(gè)細(xì)節(jié)的地方
1.0.5和 2 * positionOffset,0.5是變化的節(jié)點(diǎn)姜钳,而透明度是0到1,所以是2 * positionOffset
2.透明度最小 0.2形耗,當(dāng)0.5或者接近哥桥。5時(shí)文字為看不到,所以這里設(shè)置最小值0.2
3.position和position+1的設(shè)定激涤,這里建議大家多看看demo中的打印拟糕,效果會(huì)更直觀
4、貓的動(dòng)畫(huà)
貓的動(dòng)畫(huà)其實(shí)很簡(jiǎn)單,就是一個(gè)幀動(dòng)畫(huà)送滞。這里是真的不打算說(shuō)侠草,想了解詳情的可以在github地址 中查看。
四犁嗅、后記
自此文章已經(jīng)結(jié)束边涕,github地址 的下載地址已經(jīng)給出,對(duì)代碼有修改建議的也可以提出褂微,相互討論功蜓。