版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、打造炫酷通用的ViewPager指示器Adapter模式適配所有sm視冏 國片 鍛子itw用Adapter適配器模式適配所有的效果,堪稱終結(jié)者效果實(shí)現(xiàn)2.1整合上一個(gè)實(shí)例:我還是還是拿上一個(gè)實(shí)例來做演示吧。這里我貼幾種常見的效果,首先聲明An droid自帶的有這個(gè)控件叫 TabLayout,大家可以自己用用試試看好用不?我也用過但是不做任何評 價(jià),自己造的輪子還是想怎么用就怎么用。我的方案播®1雙12主建場芙妝i殳計(jì)師有案拆改Item布局不一樣,還有上面是圖片下面是文字選中的還有一些奇葩的效果如每個(gè)頭部 效果各不相同等等,我們都要去適配。2.2 實(shí)現(xiàn)思路:我在老早的時(shí)候用過 Vie
2、wPageIndicator ,還沒畢業(yè)出來工作的時(shí)候, 好不好用我也 不做評價(jià), 就是那個(gè)時(shí)候搞了一晚上沒搞出來第二天一看原來是 activity 的 Theme 主題沒有 配置,大家手上肯定也有類似的效果也都可以用,只是以個(gè)人的理解來自己造一個(gè)輪子。2.2.1 控件肯定是繼承 ScrollView 因?yàn)榭梢宰笥一瑒?dòng),如果再去自定義 ViewGroup 肯定不劃算。2.2.2 怎樣才能適合所有的效果,難道我們把所有可能出現(xiàn)的效果都寫一遍嗎?這 的確不太可能,所以肯定采用 Adapter 適配器模式。2.2.3 我們先動(dòng)起來從簡單的入手,先做到動(dòng)態(tài)的添加不同的布局條目再說吧。2.3 自定義 T
3、rackIndicatorView 動(dòng)態(tài)添加布局:這里為了適配所有效果,所以決定采用適配器Adapter 設(shè)計(jì)模式,上面也提到過。至于什么是適配器模式大家需要看一下這個(gè)1. 模式介紹1.1 模式的定義:適配器模式把一個(gè)類的接口變換成客戶端所期待的另一種接口, 從而使原本因接口 不匹配而無法在一起工作的兩個(gè)類能夠在一起工作。1.2 模式的使用場景:用電源接口做例子,筆記本電腦的電源一般都是接受 5V 的電壓,但是我們生活中 的電線電壓一般都是 220V 的輸出。這個(gè)時(shí)候就出現(xiàn)了不匹配的狀況,在軟件開發(fā)中我們稱 之為接口不兼容, 此時(shí)就需要適配器來進(jìn)行一個(gè)接口轉(zhuǎn)換。 在軟件開發(fā)中有一句話正好體現(xiàn)
4、了這點(diǎn):任何問題都可以加一個(gè)中間層來解決。這個(gè)層我們可以理解為這里的 Adapter 層, 通過這層來進(jìn)行一個(gè)接口轉(zhuǎn)換就達(dá)到了兼容的目的。2.模式的簡單實(shí)現(xiàn)2 .1簡單實(shí)現(xiàn)的介紹:在上述電源接口這個(gè)示例中, 5V 電壓就是 Target 接口, 220v 電壓就是 Adaptee 類, 而將電壓從 220V 轉(zhuǎn)換到 5V 就是 Adapter 。2 .2 類適配器模式 :* Target 角色*/public interface FiveV olt public int getV olt5();/* Adaptee 角色 , 需要被轉(zhuǎn)換的對象*/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 角色給出了需要的目標(biāo)接口,而 Adaptee 類則是需要被轉(zhuǎn)換的對象。 Adapter 則 是將 Volt220 轉(zhuǎn)換成 Target 的接口。對應(yīng)的是 Target 的目標(biāo)是要獲取 5V 的輸出電壓,而 Adaptee 即正常輸出電壓是 220V ,此時(shí)我們就需要電源適配器類將220V
6、的電壓轉(zhuǎn)換為 5V電壓,解決接口不兼容的問題。public class Test public static void main(String args) ClassAdapter adapter = new ClassAdapter();System.out.println(" 輸出電壓 : " + adapter.getVolt5();2 .3.Android源碼中的模式實(shí)現(xiàn)與類的適配器模式一樣,對象的適配器模式把被適配的類的API 轉(zhuǎn)換成為目標(biāo)類的API ,與類的適配器模式不同的是,對象的適配器模式不是使用繼承關(guān)系連接到Adaptee類,而是使用代理關(guān)系連接到 Ada
7、ptee類。從圖2可以看出,Adaptee類(Volt220 )并沒有g(shù)etVolt5()方法,而客戶端則 期待這個(gè)方法。為使客戶端能夠使用Adaptee類,需要提供一個(gè)包裝類 Adapter。這個(gè)包裝類包裝了一個(gè) Adaptee的實(shí)例,從而此包裝類能夠把 Adaptee的API與Target類的API銜接起來。 Adapter 與 Adaptee 是委派關(guān)系,這決定了適配器模式是對象的。/* Target 角色*/public interface FiveV olt public int getV olt5();/* Adaptee 角色 , 需要被轉(zhuǎn)換的對象 */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類適配器和對象適配器的權(quán)衡* 類適配器使用對象繼
9、承的方式,是靜態(tài)的定義方式;而對象適配器使用對象 組合的方式,是動(dòng)態(tài)組合的方式。 對于類適配器,由于適配器直接繼承了Adaptee,使得適配器不能和 Adaptee的子類一起工作,因?yàn)槔^承是靜態(tài)的關(guān)系,當(dāng)適配器繼承了 Adaptee 后,就不可能再去處理 Adaptee 的子類了。對于對象適配器,一個(gè)適配器可以把多種不同的源適配到同一個(gè)目標(biāo)。 換言之, 同一個(gè)適配器可以把源類和它的子類都適配到目標(biāo)接口。 因?yàn)閷ο筮m配器采用的是 對象組合的關(guān)系,只要對象類型正確,是不是子類都無所謂。* 對于類適配器, 適配器可以重定義 Adaptee 的部分行為, 相當(dāng)于子類覆蓋父類 的部分實(shí)現(xiàn)方法。對于對象適
10、配器,要重定義 Adaptee 的行為比較困難,這種情況下,需要 定義 Adaptee 的子類來實(shí)現(xiàn)重定義,然后讓適配器組合子類。雖然重定義 Adaptee 的行為比 較困難,但是想要增加一些新的行為則方便的很, 而且新增加的行為可同時(shí)適用于所有的源。* 對于類適配器,僅僅引入了一個(gè)對象,并不需要額外的引用來間接得到Adaptee。對于對象適配器,需要額外的引用來間接得到Adaptee。建議盡量使用對象適配器的實(shí)現(xiàn)方式,多用合成 /聚合、少用繼承。當(dāng)然,具體問 題具體分析,根據(jù)需要來選用實(shí)現(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;/ 解析、設(shè)置、緩存 convertView 以及相關(guān)內(nèi)容Overridepublic View getView(int position, View convertView, ViewGroup parent) ViewHolder holder = null;/ Item View 的復(fù)用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 需要能夠顯示各式各樣的視圖,每個(gè)人需要 的顯示效果各不相同, 顯示的數(shù)據(jù)類型、 數(shù)量等也千變?nèi)f化。 那么如何隔離這種變化尤為重 要。Android 的做法是增加一個(gè) Adapter 層來應(yīng)對變化,將 ListView 需要的接口抽象到 Adapter 對象中,這樣只要用戶實(shí)現(xiàn)了 Adapter 的接口, ListView 就可以按照用戶設(shè)定的顯 示效果、數(shù)量、數(shù)據(jù)來顯示特定的 Item View 。通過代理數(shù)據(jù)集來告知
15、ListView 數(shù)據(jù)的個(gè)數(shù) ( getCount 函數(shù) )以及每個(gè)數(shù)據(jù)的類型 ( getItem 函數(shù) ) ,最重要的是要解決 Item View 的輸出。 Item View 千變?nèi)f化,但終究它都是 View 類型, Adapter 統(tǒng)一將 Item View 輸出為 View ( getView 函數(shù) ),這樣就很好的應(yīng)對了 Item View 的可變性。那么 ListView 是如何通過 Adapter 模式 ( 不止 Adapter 模式 ) 來運(yùn)作的呢 ?我們一起 來看一看。ListView 繼承自 AbsListView , Adapter 定義在 AbsListView 中,我
16、們看一看這個(gè)類。public abstract class AbsListView extends AdapterView<ListAdapter> implements TextWatcher,ViewTreeObserver.OnGlobalLayoutListener, Filter.FilterListener, ViewTreeObserver.OnTouchModeChangeListener, RemoteViewsAdapter.RemoteAdapterConnectionCallback ListAdapter mAdapter ;/ 關(guān)聯(lián)到 Window 時(shí)調(diào)
17、用的函數(shù)Overrideprotected void onAttachedToWindow() super.onAttachedToWindow();/ 代碼省略/ 給適配器注冊一個(gè)觀察者 ,該模式下一篇介紹。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ù)量 ,調(diào)用的是 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;/ 獲取一個(gè) Item ViewView obtainView(int position, boolean isScrap) isScrap0 = false;View scrapView;/ 從緩存的 Item View 中獲取 ,ListView 的復(fù)用機(jī)制就在這里 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 模式的應(yīng)用、 復(fù)用 Item View 的邏輯、 布局 Item View 的邏輯等。子類只需要覆寫特定的方法即可實(shí)現(xiàn)集合視圖的功能,例如 ListView 。ListView 中的相
22、關(guān)方法。Overrideprotected void layoutChildren() / 代碼省略try super.layoutChildren();invalidate();/ 代碼省略/ 根據(jù)布局模式來布局 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ù)中根據(jù)布局模式來布局 Item View。Item View的個(gè)數(shù)、樣式都通過 Adapter對應(yīng)的方法來獲取
28、,獲取個(gè)數(shù)、Item View之后,將這些 Item View 布局到 ListView 對應(yīng)的坐標(biāo)上,再加上 Item View 的復(fù)用機(jī)制,整 個(gè) ListView 就基本運(yùn)轉(zhuǎn)起來了。當(dāng)然這里的 Adapter 并不是經(jīng)典的適配器模式,但是卻是對象適配器模式的優(yōu)秀示例, 也很好的體現(xiàn)了面向?qū)ο蟮囊恍┗驹瓌t。這里的 Target 角色和 Adapter 角色融合在一起, Adapter中的方法就是目標(biāo)方法; 而Adaptee角色就是ListView的數(shù)據(jù)集與Item View , Adapter 代理數(shù)據(jù)集,從而獲取到數(shù)據(jù)集的個(gè)數(shù)、元素。通過增加 Adapter 一層來將 Item Vie
29、w 的操作抽象起來, ListView 等集合視圖通過 Adapter 對象獲得 Item 的個(gè)數(shù)、數(shù)據(jù)元素、 Item View 等,從而達(dá)到適配各種數(shù)據(jù)、各種 Item 視圖 的效果。因?yàn)?Item View 和數(shù)據(jù)類型千變?nèi)f化, Android 的架構(gòu)師們將這些變化的部分交給 用戶來處理,通過 getCount、 getItem、 getView 等幾個(gè)方法抽象出來,也就是將 Item View 的構(gòu)造過程交給用戶來處理, 靈活地運(yùn)用了適配器模式, 達(dá)到了無限適配、 擁抱變化的目的。4.雜談優(yōu)點(diǎn)與缺點(diǎn)優(yōu)點(diǎn)更好的復(fù)用性系統(tǒng)需要使用現(xiàn)有的類, 而此類的接口不符合系統(tǒng)的需要。 那么通過適配器模
30、式就 可以讓這些功能得到更好的復(fù)用。更好的擴(kuò)展性在實(shí)現(xiàn)適配器功能的時(shí)候, 可以調(diào)用自己開發(fā)的功能, 從而自然地?cái)U(kuò)展系統(tǒng)的功能。 缺點(diǎn)過多的使用適配器, 會(huì)讓系統(tǒng)非常零亂, 不易整體進(jìn)行把握。 比如,明明看到調(diào)用的是 A 接口,其實(shí)內(nèi)部被適配成了 B 接口的實(shí)現(xiàn),一個(gè)系統(tǒng)如果太多出現(xiàn)這種情況,無異于一 場災(zāi)難。因此如果不是很有必要,可以不使用適配器,而是直接對系統(tǒng)進(jìn)行重構(gòu)。比如,明明看到調(diào)用的是 A 接口這是理論篇,但是仔細(xì)看過我博客的哥們應(yīng)該知道我 其實(shí) Adapter 設(shè)計(jì)模式理論與實(shí)踐相結(jié)合寫過很多效果和框架了。 這里不做過多的講解, 寫 著寫著看著看著就會(huì)了就理解了。2.3.1 我們再也
31、不能直接傳字符串?dāng)?shù)組或是傳對象數(shù)組過去讓自定義 View 去處理 了,所以我們先確定一個(gè)自定義的Adapter 類,getCount()和 getView(int position,ViewGroupparent) 先用這兩個(gè)方法吧后面想到了再說。* Created by Darren on 2016/12/7.* Email: 240336124* Description: 指示器的適配器 */public abstract class IndicatorBaseAdapter/ 獲取總的條數(shù)public abstract int getCount();/ 根據(jù)當(dāng)前的位置獲取 Viewpub
32、lic abstract View getView(int position,ViewGroup parent);2.3.2 然 后 我 們 來 實(shí) 現(xiàn) 指 示 器 的 自 定 義 View , TrackIndicatorView 繼 承 自HorizontalScrollView 。然后我們利用傳遞過來的 Adapter 再去動(dòng)態(tài)的添加, 我這里就直接上 代碼吧/* Created by Darren on 2016/12/13.* Email: 240336124* Description: ViewPager 指示器*/public class TrackIndicatorView e
33、xtends HorizontalScrollView / 自定義適配器private IndicatorBaseAdapter mAdapter;/ Item 的容器因?yàn)?ScrollView 只允許加入一個(gè)孩子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 個(gè)數(shù)int count = mAdapter.getCount();/ 動(dòng)態(tài)添加到布局容器for (int i = 0; i < count; i+) View indicatorView = mAdapter.getView(i, mIndicatorContainer); mIndicatorContainer.addView(indicatorView);效果可想而知, 可以寫一個(gè) Activity 測試一下, 目前可以動(dòng)態(tài)
36、的添加多個(gè)不同樣式的布 局,如果超出一個(gè)屏幕可以左右滑動(dòng),我這里就不做演示,待會(huì)一起吧。2.3.3 動(dòng)態(tài)的制定指示器 Item 的寬度:目前我們雖然能夠動(dòng)態(tài)的去添加各種布局,但是 Item 的寬度是任意的,我們需要 在布局文件中指定一屏顯示多少個(gè),如果沒有指定那么就獲取 Item 中最寬的一個(gè),如果不 夠一屏顯示就默認(rèn)顯示一屏。 我們需要使用自定義屬性, 這里就不做過多的講, 實(shí)在不行大 家就自己去看看有關(guān)自定義屬性的博客或是直接 google 搜索一下。/ 獲取一屏顯示多少個(gè) Item, 默認(rèn)是 0private int mTabVisibleNums = 0;/ 每個(gè) Item 的寬度pr
37、ivate int mItemWidth = 0;public TrackIndicatorView(Context context, AttributeSet attrs, int defStyleAttr) super(context, attrs, defStyleAttr);/ 之前代碼省略 ./ 獲取自定義屬性值 一屏顯示多少個(gè)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+) / 指定每個(gè) Item 的寬度 mIndicatorContainer.getChildAt(i).getLayoutParams().width mItemWidth;Log.e(TAG, "mItemWidth -> " + mItemWidth);* 獲取每一個(gè)條目的寬度*/public int getItemWidth() int itemWidth = 0;/ 獲取當(dāng)前控件的寬度int width = getWidth();if (mTabVisibleNums != 0) / 在布局文件中指定一屏幕顯示多少個(gè) itemWidth
40、= width / mTabVisibleNums; return itemWidth;/ 如果沒有指定獲取最寬的一個(gè)作為 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;/ 如果不足一個(gè)屏那么寬度就為 width/mItemCountsif (allWidth < width) itemWidth = width / mItemCounts;return itemWidth;4 個(gè),目前我們各種情況都測試了一下,一種是直接在布局文件中指定一屏可見顯示 一種是不指定就默認(rèn)以最大的 Item 的寬度為準(zhǔn),最后一種就是不指定又不足一個(gè)屏幕默認(rèn)就顯示一屏。看一下效果吧2.4 結(jié)合 View
42、Pager接下來我們就需要結(jié)合ViewPager 了,也就需要實(shí)現(xiàn)一系列重要的效果:2.4.1. 當(dāng)ViewPager滾動(dòng)的時(shí)候頭部需要自動(dòng)將當(dāng)前Item滾動(dòng)到最中心;2.4.2. 點(diǎn)擊Item之后ViewPager能夠切換到對應(yīng)的頁面;Adapter2.4.3. 需要頁面切換之后需要回調(diào),讓用戶切換當(dāng)前選中的狀態(tài),需要在 中增加方法;2.4.4. 有些效果需要加入指示器,但并不是每種效果都需要2.4.1.當(dāng)ViewPager滾動(dòng)的時(shí)候頭部自動(dòng)將當(dāng)前Item滾動(dòng)到最中心ViewPager我們目前不光需要 Adapter,還需要一個(gè)參數(shù)就是 ViewPager,需要監(jiān)聽 的滾動(dòng)事件*重載一個(gè)se
43、tAdapter的方法* param adapter 適配器* param viewPager 聯(lián)動(dòng)的 ViewPager*/public void setAdapter(I ndicatorBaseAdapter adapter, ViewPager viewPager) /直接調(diào)用重載方法setAdapter(adapter);II為ViewPager添加滾動(dòng)監(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滾動(dòng)的時(shí)候會(huì)不斷的調(diào)用該方法Log.e(TAG ,"position -> "+positio n+"positio nO ffset -> "+positio nO ffset);/在不斷滾動(dòng)的時(shí)候讓頭部的當(dāng)前Item 直保持在最中心in dicatorScrollTo(positi on ,positi onO ffset);*不斷的滾動(dòng)頭部*/private void indicator
45、ScrollTo(int position, float positionOffset) /當(dāng)前的偏移量 int curre ntOffset = (int) (positi on + positi onO ffset) * mltemWidth);/原始的左邊的偏移量 in t origin LeftOffset = (getWidth()-mltemWidth)/2;/當(dāng)前應(yīng)該滾動(dòng)的位置 int scrollToOffset = curre ntOffset - origi nLeftOffset; / 調(diào)用 ScrollView 的 scrollTo 方法scrollTo(scrollT
46、oOffset,0);目前我們滾動(dòng)鑒醮的時(shí)蟆,當(dāng)前指示器條目會(huì)一直保持在攝中心,口】皿潤 代碼我就沒貼出來了,遠(yuǎn)個(gè)待會(huì)可旦下載我的濾瑪看看.我們看看效杲2.4.2.點(diǎn)擊Item之后ViewPager能夠切換到對應(yīng)的頁面public void setAdapter(IndicatorBaseAdapter adapter) if (er = null) throw new NullPointerException("Adapter cannot be null!"); this.mAdapter = adapter;/ 獲取 Item 個(gè)數(shù)int count = mAdapt
47、er.getCount();/ 動(dòng)態(tài)添加到布局容器for (int i = 0; i < count; i+) View indicatorView = mAdapter.getView(i, mIndicatorContainer); mIndicatorContainer.addView(indicatorView); switchIndicatorClick(indicatorView,i);* Indicator 條目點(diǎn)擊對應(yīng)切換 ViewPager */private void switchIndicatorClick(View indicatorView, final int
48、 position) indicatorView.setOnClickListener(new OnClickListener() Overridepublic void onClick(View v) if(mViewPager != null)/ 對應(yīng)切換 ViewPager mViewPager.setCurrentItem(position);/ IndicatorItem 對應(yīng)滾動(dòng)到最中心 indicatorSmoothScrollTo(position););int scrollToOffset = currentOffset - originLeftOffset;/ smooth
49、ScrollTosmoothScrollTo(scrollToOffset,0);我們運(yùn)行起來之后會(huì)發(fā)現(xiàn)一個(gè)問題, 我們點(diǎn)擊會(huì)切換對應(yīng)的 ViewPager 但是這個(gè)時(shí)候還 是會(huì)調(diào)用 onPageScrolled() 方法,這個(gè)就比較 dan 疼,所以我們必須解決,如果是點(diǎn)擊我就 不讓其執(zhí)行 onPageScrolled() 里面的代碼。2.4.3. 需要頁面切換之后需要回調(diào),讓用戶切換當(dāng)前選中的狀態(tài),需要在 Adapter 中增加方法在 Adapter 中增加兩個(gè)回調(diào)方法,一個(gè)是高亮當(dāng)前選中方法 highLightIndicator(View view) ,恢復(fù)默認(rèn)方法 restoreInd
50、icator(View view) ,這兩個(gè)方法可以不用寫成抽象的,為了 方便我們干脆使用泛型* Created by Darren on 2016/12/7.* Email: 240336124* Description: 指示器的適配器*/public abstract class IndicatorBaseAdapter<Q extends View> / 獲取總的條數(shù) public abstract int getCount();/ 根據(jù)當(dāng)前的位置獲取 Viewpublic abstract Q getView(int position, ViewGroup parent)
51、;/ 高亮當(dāng)前位置public void highLightIndicator(Q indicatorView)/ 重置當(dāng)前位置 public void restoreIndicator(Q indicatorView)TrackIndicatorViewOverride public void onPageSelected(int position) / 重置上一個(gè)位置的狀態(tài) View lastView = mIndicatorContainer.getChildAt(mCurrentPosition);mAdapter.restore In dicator(lastView); /高亮當(dāng)前
52、位置的狀態(tài)mCurre ntPositi on = positi on; highLight In dicator(mCurre ntPositi on);*高亮當(dāng)前位置*/private void highLight In dicator(i nt positi on) View curre ntView = mln dicatorC ontain er.getChildAt(positi on); mAdapter.highLightI ndicator(curre ntView);謖子當(dāng)前這里下吧。一步兩步一步兩步總算是快到頭了,接下來我們只需要加入指示器就可以了,面涉及到屬性動(dòng)畫,如果
53、不是很了解那就去看一下我的視頻或者去google官網(wǎng)看2.4.4. 有些效果需要加入指示器,但并不是每種效果都需要* Created by Darren on 2016/12/7.* Email: 240336124* Descriptio n:指示器的容器包括下標(biāo)*/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)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 小麥滴灌安裝合同(2篇)
- 醫(yī)院建筑分布式光伏發(fā)電方案
- IT技術(shù)合作協(xié)議范本
- 國有企業(yè)黨建工作督導(dǎo)檢查實(shí)施方案
- 南寧2024年統(tǒng)編版小學(xué)五年級英語第一單元期中試卷
- 制造業(yè)員工三基培訓(xùn)考核標(biāo)準(zhǔn)
- 注塑機(jī)節(jié)能評估與優(yōu)化方案
- 2024-2025學(xué)年河北省高三上學(xué)期省級聯(lián)測語文試題及答案
- 施工現(xiàn)場新冠防疫及衛(wèi)生方案
- 體育場館張拉膜安裝方案
- (新版)糖尿病知識競賽考試題庫300題(含答案)
- CHT 1027-2012 數(shù)字正射影像圖質(zhì)量檢驗(yàn)技術(shù)規(guī)程(正式版)
- 教學(xué)成果獎(jiǎng)培育思考
- 河北省廊坊市藥品零售藥店企業(yè)藥房名單目錄
- 畢業(yè)設(shè)計(jì)(論文)叉車液壓系統(tǒng)設(shè)計(jì)
- 研發(fā)項(xiàng)目立項(xiàng)管理流程總體思路.doc
- 室內(nèi)裝飾裝修工程施工組織設(shè)計(jì)方案(完整版)
- 榆林市第十二中學(xué)第二個(gè)五年發(fā)展規(guī)劃
- 日本城市生活垃圾處理現(xiàn)狀及發(fā)展趨勢
- 盤縣紅果鎮(zhèn)上紙廠煤礦(技改)45萬ta項(xiàng)目環(huán)境影響評價(jià)報(bào)告書
- 維修電工高級實(shí)操考核內(nèi)容
評論
0/150
提交評論