引導(dǎo)頁(yè)之從零開(kāi)始

一、前言
最近所開(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ì)代碼有修改建議的也可以提出,相互討論。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容