版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、打造炫酷通用的ViewPager指示器Adapter模式適配所有sm視冏 國片 鍛子itw用Adapter適配器模式適配所有的效果,堪稱終結者效果實現(xiàn)2.1整合上一個實例:我還是還是拿上一個實例來做演示吧。這里我貼幾種常見的效果,首先聲明An droid自帶的有這個控件叫 TabLayout,大家可以自己用用試試看好用不?我也用過但是不做任何評 價,自己造的輪子還是想怎么用就怎么用。我的方案播®1雙12主建場芙妝i殳計師有案拆改Item布局不一樣,還有上面是圖片下面是文字選中的還有一些奇葩的效果如每個頭部 效果各不相同等等,我們都要去適配。2.2 實現(xiàn)思路:我在老早的時候用過 Vie
2、wPageIndicator ,還沒畢業(yè)出來工作的時候, 好不好用我也 不做評價, 就是那個時候搞了一晚上沒搞出來第二天一看原來是 activity 的 Theme 主題沒有 配置,大家手上肯定也有類似的效果也都可以用,只是以個人的理解來自己造一個輪子。2.2.1 控件肯定是繼承 ScrollView 因為可以左右滑動,如果再去自定義 ViewGroup 肯定不劃算。2.2.2 怎樣才能適合所有的效果,難道我們把所有可能出現(xiàn)的效果都寫一遍嗎?這 的確不太可能,所以肯定采用 Adapter 適配器模式。2.2.3 我們先動起來從簡單的入手,先做到動態(tài)的添加不同的布局條目再說吧。2.3 自定義 T
3、rackIndicatorView 動態(tài)添加布局:這里為了適配所有效果,所以決定采用適配器Adapter 設計模式,上面也提到過。至于什么是適配器模式大家需要看一下這個1. 模式介紹1.1 模式的定義:適配器模式把一個類的接口變換成客戶端所期待的另一種接口, 從而使原本因接口 不匹配而無法在一起工作的兩個類能夠在一起工作。1.2 模式的使用場景:用電源接口做例子,筆記本電腦的電源一般都是接受 5V 的電壓,但是我們生活中 的電線電壓一般都是 220V 的輸出。這個時候就出現(xiàn)了不匹配的狀況,在軟件開發(fā)中我們稱 之為接口不兼容, 此時就需要適配器來進行一個接口轉換。 在軟件開發(fā)中有一句話正好體現(xiàn)
4、了這點:任何問題都可以加一個中間層來解決。這個層我們可以理解為這里的 Adapter 層, 通過這層來進行一個接口轉換就達到了兼容的目的。2.模式的簡單實現(xiàn)2 .1簡單實現(xiàn)的介紹:在上述電源接口這個示例中, 5V 電壓就是 Target 接口, 220v 電壓就是 Adaptee 類, 而將電壓從 220V 轉換到 5V 就是 Adapter 。2 .2 類適配器模式 :* Target 角色*/public interface FiveV olt public int getV olt5();/* Adaptee 角色 , 需要被轉換的對象*/public class Volt220 pub
5、lic int getV olt220() return 220;/ adapter 角色public class ClassAdapter extends Volt220 implements FiveV olt Overridepublic int getV olt5() return 5;Target 角色給出了需要的目標接口,而 Adaptee 類則是需要被轉換的對象。 Adapter 則 是將 Volt220 轉換成 Target 的接口。對應的是 Target 的目標是要獲取 5V 的輸出電壓,而 Adaptee 即正常輸出電壓是 220V ,此時我們就需要電源適配器類將220V
6、的電壓轉換為 5V電壓,解決接口不兼容的問題。public class Test public static void main(String args) ClassAdapter adapter = new ClassAdapter();System.out.println(" 輸出電壓 : " + adapter.getVolt5();2 .3.Android源碼中的模式實現(xiàn)與類的適配器模式一樣,對象的適配器模式把被適配的類的API 轉換成為目標類的API ,與類的適配器模式不同的是,對象的適配器模式不是使用繼承關系連接到Adaptee類,而是使用代理關系連接到 Ada
7、ptee類。從圖2可以看出,Adaptee類(Volt220 )并沒有getVolt5()方法,而客戶端則 期待這個方法。為使客戶端能夠使用Adaptee類,需要提供一個包裝類 Adapter。這個包裝類包裝了一個 Adaptee的實例,從而此包裝類能夠把 Adaptee的API與Target類的API銜接起來。 Adapter 與 Adaptee 是委派關系,這決定了適配器模式是對象的。/* Target 角色*/public interface FiveV olt public int getV olt5();/* Adaptee 角色 , 需要被轉換的對象 */public class
8、Volt220 public int getV olt220() return 220;/ 對象適配器模式public class ObjectAdapter implements FiveV olt Volt220 mV olt220;public ObjectAdapter(V olt220 adaptee) mVolt220 = adaptee;public int getV olt220() return mV olt220.getV olt220();Overridepublic int getV olt5() return 5;2 4類適配器和對象適配器的權衡* 類適配器使用對象繼
9、承的方式,是靜態(tài)的定義方式;而對象適配器使用對象 組合的方式,是動態(tài)組合的方式。 對于類適配器,由于適配器直接繼承了Adaptee,使得適配器不能和 Adaptee的子類一起工作,因為繼承是靜態(tài)的關系,當適配器繼承了 Adaptee 后,就不可能再去處理 Adaptee 的子類了。對于對象適配器,一個適配器可以把多種不同的源適配到同一個目標。 換言之, 同一個適配器可以把源類和它的子類都適配到目標接口。 因為對象適配器采用的是 對象組合的關系,只要對象類型正確,是不是子類都無所謂。* 對于類適配器, 適配器可以重定義 Adaptee 的部分行為, 相當于子類覆蓋父類 的部分實現(xiàn)方法。對于對象適
10、配器,要重定義 Adaptee 的行為比較困難,這種情況下,需要 定義 Adaptee 的子類來實現(xiàn)重定義,然后讓適配器組合子類。雖然重定義 Adaptee 的行為比 較困難,但是想要增加一些新的行為則方便的很, 而且新增加的行為可同時適用于所有的源。* 對于類適配器,僅僅引入了一個對象,并不需要額外的引用來間接得到Adaptee。對于對象適配器,需要額外的引用來間接得到Adaptee。建議盡量使用對象適配器的實現(xiàn)方式,多用合成 /聚合、少用繼承。當然,具體問 題具體分析,根據需要來選用實現(xiàn)方式,最適合的才是最好的。3 .Android ListView 中的 Adapter 模式在開發(fā)過程中
11、 ,ListView 的 Adapter 是我們最為常見的類型之一。一般的用法大致如下 :/ 適配器public class MyAdapter extends BaseAdapterprivate LayoutInflater mInflater;List<String> mDatas ;public MyAdapter(Context context, List<String> datas)this.mInflater = LayoutInflater.from(context);mDatas = datas ;Overridepublic int getCount
12、() return mDatas.size();Overridepublic String getItem(int pos) return mDatas.get(pos);Overridepublic long getItemId(int pos) return pos;/ 解析、設置、緩存 convertView 以及相關內容Overridepublic View getView(int position, View convertView, ViewGroup parent) ViewHolder holder = null;/ Item View 的復用if (convertView =
13、 null) holder = new ViewHolder();convertView = mInflater.inflate(R.layout.my_listview_item, null); / 獲取 title holder.title = (TextView)convertView.findViewById(R.id.title);convertView.setTag(holder); else holder = (ViewHolder)convertView.getTag();holder.title.setText(mDatas.get(position);return conv
14、ertView;這看起來似乎還挺麻煩的,看到這里我們不禁要問, ListView 為什么要使用 Adapter 模 式呢?我們知道,作為最重要的 View ,ListView 需要能夠顯示各式各樣的視圖,每個人需要 的顯示效果各不相同, 顯示的數(shù)據類型、 數(shù)量等也千變萬化。 那么如何隔離這種變化尤為重 要。Android 的做法是增加一個 Adapter 層來應對變化,將 ListView 需要的接口抽象到 Adapter 對象中,這樣只要用戶實現(xiàn)了 Adapter 的接口, ListView 就可以按照用戶設定的顯 示效果、數(shù)量、數(shù)據來顯示特定的 Item View 。通過代理數(shù)據集來告知
15、ListView 數(shù)據的個數(shù) ( getCount 函數(shù) )以及每個數(shù)據的類型 ( getItem 函數(shù) ) ,最重要的是要解決 Item View 的輸出。 Item View 千變萬化,但終究它都是 View 類型, Adapter 統(tǒng)一將 Item View 輸出為 View ( getView 函數(shù) ),這樣就很好的應對了 Item View 的可變性。那么 ListView 是如何通過 Adapter 模式 ( 不止 Adapter 模式 ) 來運作的呢 ?我們一起 來看一看。ListView 繼承自 AbsListView , Adapter 定義在 AbsListView 中,我
16、們看一看這個類。public abstract class AbsListView extends AdapterView<ListAdapter> implements TextWatcher,ViewTreeObserver.OnGlobalLayoutListener, Filter.FilterListener, ViewTreeObserver.OnTouchModeChangeListener, RemoteViewsAdapter.RemoteAdapterConnectionCallback ListAdapter mAdapter ;/ 關聯(lián)到 Window 時調
17、用的函數(shù)Overrideprotected void onAttachedToWindow() super.onAttachedToWindow();/ 代碼省略/ 給適配器注冊一個觀察者 ,該模式下一篇介紹。if (mAdapter != null && mDataSetObserver = null) mDataSetObserver = new AdapterDataSetObserver(); mAdapter.registerDataSetObserver(mDataSetObserver);/ Data may have changed while we were
18、detached. Refresh. mDataChanged = true;mOldItemCount = mItemCount/ 獲取 Item 的數(shù)量 ,調用的是 mAdapter 的 getCount 方法 mItemCount = mAdapter.getCount();mIsAttached = true;/* 子類需要覆寫 layoutChildren() 函數(shù)來布局 child view, 也就是 Item View */Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) su
19、per.onLayout(changed, l, t, r, b);mInLayout = true;if (changed) int childCount = getChildCount();for (int i = 0; i < childCount; i+) getChildAt(i).forceLayout();mRecycler.markChildrenDirty();if (mFastScroller != null && mItemCount != mOldItemCount) mFastScroller.onItemCountChanged(mOldIte
20、mCount, mItemCount);/ 布局 Child ViewlayoutChildren();mInLayout = false;mOverscrollMax = (b - t) / OVERSCROLL_LIMIT_DIVISOR;/ 獲取一個 Item ViewView obtainView(int position, boolean isScrap) isScrap0 = false;View scrapView;/ 從緩存的 Item View 中獲取 ,ListView 的復用機制就在這里 scrapView = mRecycler.getScrapView(positio
21、n);View child;if (scrapView != null) / 代碼省略child = mAdapter.getView(position, scrapView, this);/ 代碼省略 else child = mAdapter.getView(position, null, this);/ 代碼省略return child;AbsListView 定義了集合視圖的框架, 比如 Adapter 模式的應用、 復用 Item View 的邏輯、 布局 Item View 的邏輯等。子類只需要覆寫特定的方法即可實現(xiàn)集合視圖的功能,例如 ListView 。ListView 中的相
22、關方法。Overrideprotected void layoutChildren() / 代碼省略try super.layoutChildren();invalidate();/ 代碼省略/ 根據布局模式來布局 Item View switch (mLayoutMode) case LAYOUT_SET_SELECTION:if (newSel != null) selfillFromSelection(newSel.getTop(),childrenTop,childrenBottom); else sel = fillFromMiddle(childrenTop, childrenBo
23、ttom);break;case LAYOUT_SYNC:sel = fillSpecific(mSyncPosition, mSpecificTop);break;case LAYOUT_FORCE_BOTTOM:sel = fillUp(mItemCount - 1, childrenBottom);adjustViewsUpOrDown();break;case LAYOUT_FORCE_TOP:mFirstPosition = 0;sel = fillFromTop(childrenTop);adjustViewsUpOrDown();break;case LAYOUT_SPECIFI
24、C:sel = fillSpecific(reconcileSelectedPosition(), mSpecificTop);break;case LAYOUT_MOVE_SELECTION:sel = moveSelection(oldSel, newSel, delta, childrenTop, childrenBottom);break;default:/ 代碼省略break;/ 從上到下填充 Item View 只是其中一種填充方式 private View fillDown(int pos, int nextTop) View selectedView = null;int en
25、d = (mBottom - mTop);if (mGroupFlags & CLIP_TO_PADDING_MASK) =CLIP_TO_PADDING_MASK) end -= mListPadding.bottom;while (nextTop < end && pos < mItemCount) / is this the selected item?boolean selected = pos = mSelectedPosition;View child = makeAndAddView(pos, nextTop, true, mListPaddi
26、ng.left,selected);nextTop = child.getBottom() + mDividerHeight; if (selected) selectedView = child;pos+;return selectedView;/ 添加 Item Viewprivate View makeAndAddView(int position, int y, boolean flow, int childrenLeft, boolean selected) View child;/ 代碼省略/ Make a new view for this position, or conver
27、t an unused view if possible child = obtainView(position, mIsScrap);/ This needs to be positioned and measured setupChild(child, position, y, flow, childrenLeft, selected, mIsScrap0);return child;ListView 覆寫了 AbsListView 中的 layoutChilden 函數(shù),在該函數(shù)中根據布局模式來布局 Item View。Item View的個數(shù)、樣式都通過 Adapter對應的方法來獲取
28、,獲取個數(shù)、Item View之后,將這些 Item View 布局到 ListView 對應的坐標上,再加上 Item View 的復用機制,整 個 ListView 就基本運轉起來了。當然這里的 Adapter 并不是經典的適配器模式,但是卻是對象適配器模式的優(yōu)秀示例, 也很好的體現(xiàn)了面向對象的一些基本原則。這里的 Target 角色和 Adapter 角色融合在一起, Adapter中的方法就是目標方法; 而Adaptee角色就是ListView的數(shù)據集與Item View , Adapter 代理數(shù)據集,從而獲取到數(shù)據集的個數(shù)、元素。通過增加 Adapter 一層來將 Item Vie
29、w 的操作抽象起來, ListView 等集合視圖通過 Adapter 對象獲得 Item 的個數(shù)、數(shù)據元素、 Item View 等,從而達到適配各種數(shù)據、各種 Item 視圖 的效果。因為 Item View 和數(shù)據類型千變萬化, Android 的架構師們將這些變化的部分交給 用戶來處理,通過 getCount、 getItem、 getView 等幾個方法抽象出來,也就是將 Item View 的構造過程交給用戶來處理, 靈活地運用了適配器模式, 達到了無限適配、 擁抱變化的目的。4.雜談優(yōu)點與缺點優(yōu)點更好的復用性系統(tǒng)需要使用現(xiàn)有的類, 而此類的接口不符合系統(tǒng)的需要。 那么通過適配器模
30、式就 可以讓這些功能得到更好的復用。更好的擴展性在實現(xiàn)適配器功能的時候, 可以調用自己開發(fā)的功能, 從而自然地擴展系統(tǒng)的功能。 缺點過多的使用適配器, 會讓系統(tǒng)非常零亂, 不易整體進行把握。 比如,明明看到調用的是 A 接口,其實內部被適配成了 B 接口的實現(xiàn),一個系統(tǒng)如果太多出現(xiàn)這種情況,無異于一 場災難。因此如果不是很有必要,可以不使用適配器,而是直接對系統(tǒng)進行重構。比如,明明看到調用的是 A 接口這是理論篇,但是仔細看過我博客的哥們應該知道我 其實 Adapter 設計模式理論與實踐相結合寫過很多效果和框架了。 這里不做過多的講解, 寫 著寫著看著看著就會了就理解了。2.3.1 我們再也
31、不能直接傳字符串數(shù)組或是傳對象數(shù)組過去讓自定義 View 去處理 了,所以我們先確定一個自定義的Adapter 類,getCount()和 getView(int position,ViewGroupparent) 先用這兩個方法吧后面想到了再說。* Created by Darren on 2016/12/7.* Email: 240336124* Description: 指示器的適配器 */public abstract class IndicatorBaseAdapter/ 獲取總的條數(shù)public abstract int getCount();/ 根據當前的位置獲取 Viewpub
32、lic abstract View getView(int position,ViewGroup parent);2.3.2 然 后 我 們 來 實 現(xiàn) 指 示 器 的 自 定 義 View , TrackIndicatorView 繼 承 自HorizontalScrollView 。然后我們利用傳遞過來的 Adapter 再去動態(tài)的添加, 我這里就直接上 代碼吧/* Created by Darren on 2016/12/13.* Email: 240336124* Description: ViewPager 指示器*/public class TrackIndicatorView e
33、xtends HorizontalScrollView / 自定義適配器private IndicatorBaseAdapter mAdapter;/ Item 的容器因為 ScrollView 只允許加入一個孩子private LinearLayout mIndicatorContainer;public TestIndicator(Context context) this(context, null);public TestIndicator(Context context, AttributeSet attrs) this(context, attrs, 0);public TestI
34、ndicator(Context context, AttributeSet attrs, int defStyleAttr) super(context, attrs, defStyleAttr);/ 初始化 Indicator 容器用來存放 itemmIndicatorContainer = new LinearLayout(context); addView(mIndicatorContainer);public void setAdapter(IndicatorBaseAdapter adapter) if (adapter = null) throw new NullPointerE
35、xception("Adapter cannot be null!");this.mAdapter = adapter;/ 獲取 Item 個數(shù)int count = mAdapter.getCount();/ 動態(tài)添加到布局容器for (int i = 0; i < count; i+) View indicatorView = mAdapter.getView(i, mIndicatorContainer); mIndicatorContainer.addView(indicatorView);效果可想而知, 可以寫一個 Activity 測試一下, 目前可以動態(tài)
36、的添加多個不同樣式的布 局,如果超出一個屏幕可以左右滑動,我這里就不做演示,待會一起吧。2.3.3 動態(tài)的制定指示器 Item 的寬度:目前我們雖然能夠動態(tài)的去添加各種布局,但是 Item 的寬度是任意的,我們需要 在布局文件中指定一屏顯示多少個,如果沒有指定那么就獲取 Item 中最寬的一個,如果不 夠一屏顯示就默認顯示一屏。 我們需要使用自定義屬性, 這里就不做過多的講, 實在不行大 家就自己去看看有關自定義屬性的博客或是直接 google 搜索一下。/ 獲取一屏顯示多少個 Item, 默認是 0private int mTabVisibleNums = 0;/ 每個 Item 的寬度pr
37、ivate int mItemWidth = 0;public TrackIndicatorView(Context context, AttributeSet attrs, int defStyleAttr) super(context, attrs, defStyleAttr);/ 之前代碼省略 ./ 獲取自定義屬性值 一屏顯示多少個TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.TrackIndicatorView);mTabVisibleNums = array.getInt(R.styleabl
38、e.TrackIndicatorView_tabVisibleNums, mTabVisibleNums);array.recycle();Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) super.onLayout(changed, l, t, r, b);if (changed) / 指定 Item 的寬度mItemWidth = getItemWidth();int itemCounts = mAdapter.getCount();for (int i = 0; i < ite
39、mCounts; i+) / 指定每個 Item 的寬度 mIndicatorContainer.getChildAt(i).getLayoutParams().width mItemWidth;Log.e(TAG, "mItemWidth -> " + mItemWidth);* 獲取每一個條目的寬度*/public int getItemWidth() int itemWidth = 0;/ 獲取當前控件的寬度int width = getWidth();if (mTabVisibleNums != 0) / 在布局文件中指定一屏幕顯示多少個 itemWidth
40、= width / mTabVisibleNums; return itemWidth;/ 如果沒有指定獲取最寬的一個作為 ItemWidthint maxItemWidth = 0;int mItemCounts = mAdapter.getCount();/ 總的寬度int allWidth = 0;for (int i = 0; i < mItemCounts; i+) View itemView = mIndicatorContainer.getChildAt(i);int childWidth = itemView.getMeasuredWidth(); maxItemWidt
41、h = Math.max(maxItemWidth, childWidth); allWidth += childWidth;itemWidth = maxItemWidth;/ 如果不足一個屏那么寬度就為 width/mItemCountsif (allWidth < width) itemWidth = width / mItemCounts;return itemWidth;4 個,目前我們各種情況都測試了一下,一種是直接在布局文件中指定一屏可見顯示 一種是不指定就默認以最大的 Item 的寬度為準,最后一種就是不指定又不足一個屏幕默認就顯示一屏??匆幌滦Ч?.4 結合 View
42、Pager接下來我們就需要結合ViewPager 了,也就需要實現(xiàn)一系列重要的效果:2.4.1. 當ViewPager滾動的時候頭部需要自動將當前Item滾動到最中心;2.4.2. 點擊Item之后ViewPager能夠切換到對應的頁面;Adapter2.4.3. 需要頁面切換之后需要回調,讓用戶切換當前選中的狀態(tài),需要在 中增加方法;2.4.4. 有些效果需要加入指示器,但并不是每種效果都需要2.4.1.當ViewPager滾動的時候頭部自動將當前Item滾動到最中心ViewPager我們目前不光需要 Adapter,還需要一個參數(shù)就是 ViewPager,需要監(jiān)聽 的滾動事件*重載一個se
43、tAdapter的方法* param adapter 適配器* param viewPager 聯(lián)動的 ViewPager*/public void setAdapter(I ndicatorBaseAdapter adapter, ViewPager viewPager) /直接調用重載方法setAdapter(adapter);II為ViewPager添加滾動監(jiān)聽事件 this.mViewPager = viewPager; mViewPager.addO nPageCha ngeListe ner(this); Overridepublic void on PageScrolled(i
44、nt positi on, float positi onO ffset,int positi onO ffsetPixels) /在ViewPager滾動的時候會不斷的調用該方法Log.e(TAG ,"position -> "+positio n+"positio nO ffset -> "+positio nO ffset);/在不斷滾動的時候讓頭部的當前Item 直保持在最中心in dicatorScrollTo(positi on ,positi onO ffset);*不斷的滾動頭部*/private void indicator
45、ScrollTo(int position, float positionOffset) /當前的偏移量 int curre ntOffset = (int) (positi on + positi onO ffset) * mltemWidth);/原始的左邊的偏移量 in t origin LeftOffset = (getWidth()-mltemWidth)/2;/當前應該滾動的位置 int scrollToOffset = curre ntOffset - origi nLeftOffset; / 調用 ScrollView 的 scrollTo 方法scrollTo(scrollT
46、oOffset,0);目前我們滾動鑒醮的時蟆,當前指示器條目會一直保持在攝中心,口】皿潤 代碼我就沒貼出來了,遠個待會可旦下載我的濾瑪看看.我們看看效杲2.4.2.點擊Item之后ViewPager能夠切換到對應的頁面public void setAdapter(IndicatorBaseAdapter adapter) if (er = null) throw new NullPointerException("Adapter cannot be null!"); this.mAdapter = adapter;/ 獲取 Item 個數(shù)int count = mAdapt
47、er.getCount();/ 動態(tài)添加到布局容器for (int i = 0; i < count; i+) View indicatorView = mAdapter.getView(i, mIndicatorContainer); mIndicatorContainer.addView(indicatorView); switchIndicatorClick(indicatorView,i);* Indicator 條目點擊對應切換 ViewPager */private void switchIndicatorClick(View indicatorView, final int
48、 position) indicatorView.setOnClickListener(new OnClickListener() Overridepublic void onClick(View v) if(mViewPager != null)/ 對應切換 ViewPager mViewPager.setCurrentItem(position);/ IndicatorItem 對應滾動到最中心 indicatorSmoothScrollTo(position););int scrollToOffset = currentOffset - originLeftOffset;/ smooth
49、ScrollTosmoothScrollTo(scrollToOffset,0);我們運行起來之后會發(fā)現(xiàn)一個問題, 我們點擊會切換對應的 ViewPager 但是這個時候還 是會調用 onPageScrolled() 方法,這個就比較 dan 疼,所以我們必須解決,如果是點擊我就 不讓其執(zhí)行 onPageScrolled() 里面的代碼。2.4.3. 需要頁面切換之后需要回調,讓用戶切換當前選中的狀態(tài),需要在 Adapter 中增加方法在 Adapter 中增加兩個回調方法,一個是高亮當前選中方法 highLightIndicator(View view) ,恢復默認方法 restoreInd
50、icator(View view) ,這兩個方法可以不用寫成抽象的,為了 方便我們干脆使用泛型* Created by Darren on 2016/12/7.* Email: 240336124* Description: 指示器的適配器*/public abstract class IndicatorBaseAdapter<Q extends View> / 獲取總的條數(shù) public abstract int getCount();/ 根據當前的位置獲取 Viewpublic abstract Q getView(int position, ViewGroup parent)
51、;/ 高亮當前位置public void highLightIndicator(Q indicatorView)/ 重置當前位置 public void restoreIndicator(Q indicatorView)TrackIndicatorViewOverride public void onPageSelected(int position) / 重置上一個位置的狀態(tài) View lastView = mIndicatorContainer.getChildAt(mCurrentPosition);mAdapter.restore In dicator(lastView); /高亮當前
52、位置的狀態(tài)mCurre ntPositi on = positi on; highLight In dicator(mCurre ntPositi on);*高亮當前位置*/private void highLight In dicator(i nt positi on) View curre ntView = mln dicatorC ontain er.getChildAt(positi on); mAdapter.highLightI ndicator(curre ntView);謖子當前這里下吧。一步兩步一步兩步總算是快到頭了,接下來我們只需要加入指示器就可以了,面涉及到屬性動畫,如果
53、不是很了解那就去看一下我的視頻或者去google官網看2.4.4. 有些效果需要加入指示器,但并不是每種效果都需要* Created by Darren on 2016/12/7.* Email: 240336124* Descriptio n:指示器的容器包括下標*/public class IndicatorContainer extends RelativeLayout private LinearLayout mIndicatorContainer;private Context mContext;/ 底部跟蹤的 Viewprivate View mBottomTrackView;pr
54、ivate String TAG = "IndicatorContainer"/ 距離左邊的初始距離private int mInitLeftMargin = 0;private RelativeLayout.LayoutParams mBottomTrackParams;private int mTabWidth;public IndicatorContainer(Context context) this(context, null);public IndicatorContainer(Context context, AttributeSet attrs) this(
55、context, attrs, 0);public IndicatorContainer(Context context, AttributeSet attrs, int defStyleAttr) super(context, attrs, defStyleAttr);this.mContext = context;Overridepublic void addView(View child) if (mIndicatorContainer = null) / 初始化容器mIndicatorContainer = new LinearLayout(mContext);RelativeLayout.LayoutParams params = new LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);super.addView(mIndicatorContainer, params);mIndicatorContai
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 食品衛(wèi)生防范條例
- 臨時網絡管理員合同
- 2025版跨境電商物流平臺入駐協(xié)議合同范本3篇
- 野生動物園保安員招聘合同
- 物業(yè)管理招投標交易費政策
- 商標一次性補償協(xié)議
- 公共廣場照明施工合作協(xié)議
- 船舶制造供貨施工合同范本
- 醫(yī)療器械維修聯(lián)盟協(xié)議
- 醫(yī)療設備召回政策與程序
- 2024年機動車檢測站質量手冊程序文件記錄表格合集(根據補充要求編制)
- 公司未來發(fā)展規(guī)劃及目標制定
- 食堂承包業(yè)績報告范文
- 2024年度餐飲店會員積分互換合同3篇
- 太陽耀斑預測研究-洞察分析
- 2024年01月11067知識產權法期末試題答案
- 化工企業(yè)銷售管理制度匯編
- 2025版國家開放大學法律事務??啤睹穹▽W(2)》期末紙質考試案例分析題庫
- 2024年全國各地化學中考試題匯編:酸和堿(含詳解)
- 廣東省深圳市2023-2024學年高一上學期期末英語試題(含答案)
- DB41T 2486-2023 叉車維護保養(yǎng)與自行檢查規(guī)范
評論
0/150
提交評論