導覽列特效-新聞類APP(比網易,今日頭條好看)

來源:互聯網
上載者:User

標籤:導航   今日頭條   網易   新聞   導覽列特效   

好久沒有寫文章了,慢慢的自己工作中遇到的問題不做積累,下次遇到還會忘。哎。。。。

周日無聊的單身程式員-唯有程式你懂的...寫著程式聽著歌也是極好的!!

最近工作中要實作類別似 今日頭條等新聞類APP頂部導航條的效果 ,不過我們這效果切換時要加上文字顏色的漸層和縮放

我不會弄動態圖片啊,求各位會的教俺下:





一:分析

今天我們要實現這種特效。

用到的開源項目有:master-nineoldandroids-library.jar這個jar包,這個是向下相容的jar包,包括android一系列的動畫。

首先我們說一下這種 日頭條等新聞類APP 的基本實現是ViewPage+Fragment+HorizontalScrollView

我們今天說的就是這個HorizontalScrollView的特效。

實現原理圖:



相信大家已經明白了大概

就是:最初時我們 初始化textview  並把選中的和正常的textview 初始化。就是中的framelayout中的2個textview 放到集合 HashMap<String, View>()中。用於保持所有textview的狀態。

至於代碼怎麼寫呢?!

android系統給我們提供了一個叫PagerSlidingTabStrip的類,在v4包中。我們把java中考出來放到我們的小明中,修改其中的代碼就可以。

我們通過viewpage來控制導航條。把viewpage傳到PagerSlidingTabStrip中,並設定監聽器,代碼如下:

public void setViewPager(ViewPager pager) {this.pager = pager;if (pager.getAdapter() == null) {throw new IllegalStateException("ViewPager does not have adapter instance.");}pager.setOnPageChangeListener(pageListener);notifyDataSetChanged();}

二、擷取使用者切換時當前View和切換至的目的View。

ViewPager也需要監聽使用者的手勢,所以肯定提供了某個方法。於是縱觀ViewPager的方法,發現了一個叫做 onPageScrolled(int position, float positionOffset, int positionOffsetPixels)的方法~~

沒錯就是這個方法:在頁面滾動時調用~

下面仔細研究下這幾個參數:

直接說測試結果:

在非第一頁與最後一頁時,滑動到下一頁,position為當前頁位置;滑動到上一頁:position為當前頁-1

positionOffset 滑動到下一頁,[0,1)區間上變化;滑動到上一頁:(1,0]區間上變化

positionOffsetPixels這個和positionOffset很像:滑動到下一頁,[0,寬度)區間上變化;滑動到上一頁:(寬度,0]區間上變化

第一頁時:滑動到上一頁position=0 ,其他基本為0 ;最後一頁滑動到下一頁 position為當前頁位置,其他兩個參數為0


豁然發現,我們需要的步驟的第二步解決了,positionOffset很適合作為,漸層,縮放的控制參數;positionOffsetPixels則可以作為平移等的控制參數。

那麼如何獲得當前View和目的View呢:

分享幾個我的歧途:

1、【錯誤】我通過getChildAt(position),getChildAt(position+1),getChildAt(position-1)獲得滑動時,左右的兩個View;乍一看,還真覺得不錯~~~在代碼寫出來,再乍效果也出不來~~錯誤原因:我們忽略一個特別大的東西,ViewPager的機制,滑動時動態載入和刪除View,ViewPager其實只會維持2到3個View,而position的範圍基本屬於無限~~

2、【錯誤】我通過getCurrentItem獲得當前的位置,然後+1,-1獲得後一個或者前一個~~正在竊喜,趕快代碼改過來,效果怎麼也不對,亂七八糟的~~仔細觀察日誌,這個getCurrentItem當使用者手指離開的螢幕,Page還在動畫執行時,就改變了~~難怪~整個滑動過程並不是固定的~~唉,心都碎了~

3、【錯誤】position在整個滑動的過程中是不變化的,而且ViewPager會儲存2個或3個View;那麼我考慮,如果是第一頁、或者最後一頁那麼我取getChildAt(0)和getChildAt(1),如果在其他頁面則為getChildAt(0),getChildAt(2),然後經過一系列的變化~我想這會總該對了吧,於是我遇到第一問題,第一頁的時候,不管左右position都為0,尼瑪,這哪個為左View,哪個為右View~~

說了這麼多錯誤,大家可以繞過這些彎路,也能從這些彎路裡面看出點什麼~

下面說正確的,其實ViewPager在添加一個View或者銷毀一個View時,是我們自己的PageAdapter中控制的,於是我們可以在ViewPager裡面維繫一個HashMap<Position,View>,然後滑動的時候,通過get(position)取出,比如上述效果,始終是右邊的View變化,要麼從小到大,要麼從大到小

那麼滑倒下一頁:左邊的View:map.get(position) ,右邊的View : map.get(position+1) . 

那麼滑倒上一頁:左邊的View : map.get(position) , 右邊的View : map.get(position+1) , 一樣的,因為滑到上一頁,position為當前頁-1


關鍵代碼:

<pre name="code" class="java">private class PageListener implements OnPageChangeListener {private int oldPosition = 0;@Overridepublic void onPageScrolled(int position, float positionOffset,int positionOffsetPixels) {currentPosition = position;currentPositionOffset = positionOffset;scrollToChild(position, (int) (positionOffset * tabsContainer.getChildAt(position).getWidth()));invalidate();if (delegatePageListener != null) {delegatePageListener.onPageScrolled(position, positionOffset,positionOffsetPixels);}if (mState == State.IDLE && positionOffset > 0) {oldPage = pager.getCurrentItem();mState = position == oldPage ? State.GOING_RIGHT: State.GOING_LEFT;}boolean goingRight = position == oldPage;if (mState == State.GOING_RIGHT && !goingRight)mState = State.GOING_LEFT;else if (mState == State.GOING_LEFT && goingRight)mState = State.GOING_RIGHT;float effectOffset = isSmall(positionOffset) ? 0 : positionOffset;View mLeft = tabsContainer.getChildAt(position);View mRight = tabsContainer.getChildAt(position + 1);if (effectOffset == 0) {mState = State.IDLE;}if (mFadeEnabled)animateFadeScale(mLeft, mRight, effectOffset, position);}@Overridepublic void onPageScrollStateChanged(int state) {if (state == ViewPager.SCROLL_STATE_IDLE) {scrollToChild(pager.getCurrentItem(), 0);mFadeEnabled = true;}if (delegatePageListener != null) {delegatePageListener.onPageScrollStateChanged(state);}}@Overridepublic void onPageSelected(int position) {// selectedPosition = position;// updateTabStyles();currentPosition = position;// set old view statueViewHelper.setAlpha(tabViews.get(oldPosition).get("normal"), 1);ViewHelper.setAlpha(tabViews.get(oldPosition).get("selected"), 0);View v_old = tabsContainer.getChildAt(oldPosition);ViewHelper.setPivotX(v_old, v_old.getMeasuredWidth() * 0.5f);ViewHelper.setPivotY(v_old, v_old.getMeasuredHeight() * 0.5f);ViewHelper.setScaleX(v_old, 1f);ViewHelper.setScaleY(v_old, 1f);// set new view statueViewHelper.setAlpha(tabViews.get(position).get("normal"), 0);ViewHelper.setAlpha(tabViews.get(position).get("selected"), 1);View v_new = tabsContainer.getChildAt(position);ViewHelper.setPivotX(v_new, v_new.getMeasuredWidth() * 0.5f);ViewHelper.setPivotY(v_new, v_new.getMeasuredHeight() * 0.5f);ViewHelper.setScaleX(v_new, 1 + ZOOM_MAX);ViewHelper.setScaleY(v_new, 1 + ZOOM_MAX);if (delegatePageListener != null) {delegatePageListener.onPageSelected(position);}// oldPosition = selectedPosition;oldPosition = currentPosition;}}



可以看到代碼:縮放view很關鍵:

View v_old = tabsContainer.getChildAt(oldPosition);ViewHelper.setPivotX(v_old, v_old.getMeasuredWidth() * 0.5f);ViewHelper.setPivotY(v_old, v_old.getMeasuredHeight() * 0.5f);ViewHelper.setScaleX(v_old, 1f);ViewHelper.setScaleY(v_old, 1f);
找到view的中心點即:setPivotX setPivotY 然後對X軸Y軸縮放。1為原始大小。>1放大,<1  且>0 縮小。

關鍵代碼是:onPageScrolled 方法的底2個參數positionOffset 滑動的百分比。

漸層通過animateFadeScale這個方法控制:

protected void animateFadeScale(View left, View right,float positionOffset, int position) {if (mState != State.IDLE) {if (left != null) {ViewHelper.setAlpha(tabViews.get(position).get("normal"),positionOffset);ViewHelper.setAlpha(tabViews.get(position).get("selected"),1 - positionOffset);float mScale = 1 + ZOOM_MAX - ZOOM_MAX * positionOffset;ViewHelper.setPivotX(left, left.getMeasuredWidth() * 0.5f);ViewHelper.setPivotY(left, left.getMeasuredHeight() * 0.5f);ViewHelper.setScaleX(left, mScale);ViewHelper.setScaleY(left, mScale);}if (right != null) {ViewHelper.setAlpha(tabViews.get(position + 1).get("normal"),1 - positionOffset);ViewHelper.setAlpha(tabViews.get(position + 1).get("selected"),positionOffset);float mScale = 1 + ZOOM_MAX * positionOffset;ViewHelper.setPivotX(right, right.getMeasuredWidth() * 0.5f);ViewHelper.setPivotY(right, right.getMeasuredHeight() * 0.5f);ViewHelper.setScaleX(right, mScale);ViewHelper.setScaleY(right, mScale);}}}



在你activity/引用的地方 中你可以直接設定TAB的顏色大小,正常色,選中色等。EG:

/** * 對PagerSlidingTabStrip的各項屬性進行賦值。 */private void setTabsValue() {// 設定Tab是自動填滿滿螢幕的tabs.setShouldExpand(true);// 設定Tab的分割線是透明的tabs.setDividerColor(Color.TRANSPARENT);// 設定Tab底部線的高度tabs.setUnderlineHeight((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, dm));// 設定Tab Indicator的高度tabs.setIndicatorHeight((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4, dm));// 設定Tab標題文字的大小tabs.setTextSize((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, dm));// 設定Tab Indicator的顏色tabs.setIndicatorColor(Color.parseColor("#45c01a"));// 設定選中Tab文字的顏色 (這是我自訂的一個方法)tabs.setSelectedTextColor(Color.parseColor("#45c01a"));//設定正常Tab文字的顏色 (這是我自訂的一個方法)tabs.setTextColor(Color.parseColor("#C231C7"));// 取消點擊Tab時的背景色tabs.setTabBackground(0);}


備忘:該代碼是在之前的一個模仿android-主介面上改的,可能會有多餘的類,忘理解!!


原始碼






導覽列特效-新聞類APP(比網易,今日頭條好看)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.