最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android 底部導(dǎo)航控件實(shí)例代碼

 更新時(shí)間:2016年03月21日 15:20:32   作者:周文凱  
這篇文章主要介紹了Android 底部導(dǎo)航控件實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下

一、先給大家展示下最終效果

通過以上可以看到,圖一是簡單的使用,圖二、圖三中為結(jié)合ViewPager共同使用,而且都可以隨ViewPager的滑動漸變色,不同點(diǎn)是圖二為選中非選中兩張圖片,圖三的選中非選中是一張圖片只是做了顏色變化。

二、 需求

我們希望做可以做成這樣的,可以在xml布局中引入控件并綁定數(shù)據(jù),在代碼中設(shè)置監(jiān)聽回調(diào),并且配置使用要非常簡單!

三、需求分析

根據(jù)我們多年做不明確需求項(xiàng)目的經(jīng)驗(yàn),以上需求還算明確。那么我們可以采用在LinearLayout添加子View控件,這個(gè)子View控件就是我們自定義的每個(gè)tab條目,當(dāng)然對LinearLayout要設(shè)置權(quán)重。

需求大致明確之后就先設(shè)計(jì)每個(gè)條目的子View控件,這個(gè)子View控件是一個(gè)可以切換狀態(tài)變化的,一張、兩張都可以切換狀態(tài)(參考圖一、圖三)。那么這個(gè)View要可以設(shè)置底部顯示的文字,設(shè)置選中時(shí)顏色、未選中時(shí)顏色、選中時(shí)圖片、未選中時(shí)圖片、文字大小、設(shè)置是否有指示點(diǎn)、設(shè)置指示點(diǎn)大小、設(shè)置指示點(diǎn)圖片等等。

四、Tab條目接口

通過需求分析,我們可以定義如下的Tab子View操作接口:

仔細(xì)的朋友會發(fā)現(xiàn),為什么在接口中沒有設(shè)置選中圖片以及設(shè)置非選中時(shí)圖片,那是因?yàn)檫@個(gè)屬性不是通用的,在不同的實(shí)現(xiàn)中再去定義。

五、Tab條目實(shí)現(xiàn)

類的繼承關(guān)系及說明:

類圖如下所示:

在TabViewBase中主要的方法就是測量,其他的都是對接口的簡單實(shí)現(xiàn)。

@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
// 得到繪制icon的寬 
int bitmapWidth = Math.min(getMeasuredWidth() - getPaddingLeft() 
- getPaddingRight(), getMeasuredHeight() - getPaddingTop() 
- getPaddingBottom() - mTextBound.height()); 
int left = getMeasuredWidth() / 2 - bitmapWidth / 2; 
int top = (getMeasuredHeight() - mTextBound.height()) / 2 - bitmapWidth / 2; 
// 設(shè)置icon的繪制范圍 
mIconRect = new Rect(left, top, left + bitmapWidth, top + bitmapWidth); 
// 設(shè)置指示點(diǎn)的范圍 
int indicatorRadius = mIndicatorSize / 2; 
int tabRealHeight = bitmapWidth + mTextBound.height(); 
mIndicatorRect = new Rect(left + tabRealHeight* 4/5 - indicatorRadius, top, left+tabRealHeight* 4/5 + indicatorRadius, top + mIndicatorSize); 
} 

在以上代碼中可以看到,測量文字的高度,用控件的高度減去文字的高度和控件的寬度對比,取較小的為圖片的大小,也就是設(shè)置的圖片要為正方形,否則會產(chǎn)生變形。

看下普通兩張圖片切換的TabView的繪制:

@Override 
protected void onDraw(Canvas canvas) { 
super.onDraw(canvas); 
setupTargetBitmap(canvas); 
drawIndicator(canvas); 
if(null != mText) { 
drawTargetText(canvas); 
} 
} 
/** 
* 繪制圖標(biāo)圖片 
* @param canvas 
*/ 
private void setupTargetBitmap(Canvas canvas) { 
canvas.drawBitmap(isSelected ? mSelectedIconBitmap : mUnselectedIconBitmap, null, mIconRect, null); 
} 
/** 
* 繪制指示點(diǎn) 
* @param canvas 
*/ 
protected void drawIndicator(Canvas canvas) { 
if(isIndicateDisplay) { 
canvas.drawBitmap(mIndicatorBitmap, null, mIndicatorRect, null); 
} 
} 
/** 
* 繪制文字 
* @param canvas 
*/ 
protected void drawTargetText(Canvas canvas) { 
mTextPaint.setColor(isSelected ? mSelectedColor : mUnselectedColor); 
canvas.drawText(mText, mIconRect.left + mIconRect.width() / 2 
- mTextBound.width() / 2, 
mIconRect.bottom + mTextBound.height(), mTextPaint); 
}

可以看到非常的簡單,就是繪制圖標(biāo)圖片以及繪制指示點(diǎn),在繪制圖標(biāo)圖片時(shí)判斷當(dāng)前條目是否在選中狀態(tài),根據(jù)是否選中來繪制不同的圖片,在繪制指示點(diǎn)的時(shí)候首先判斷下是否設(shè)置了顯示指示點(diǎn)。如果有底部文字,那么久繪制底部文字。
在ViewPager兩張圖片圖片的時(shí),我們再把效果圖拿過來觀察下:

這里有兩種模式,即隨著ViewPager的滾動圖標(biāo)漸變及普通變化。OK,了解之后我們就能很輕松的來編寫它的繪制了,可以通過繪制兩張圖片,但是在繪制的時(shí)候控制它的透明度就可以啦,是不是也很簡單。

@Override 
protected void onDraw(Canvas canvas) { 
super.onDraw(canvas); 
int alpha = (int) Math.ceil((255 * mAlpha)); 
drawSourceBitmap(canvas, alpha); 
drawTargetBitmap(canvas, alpha); 
if(null != mText) { 
drawSourceText(canvas, alpha); 
drawTargetText(canvas, alpha); 
} 
drawIndicator(canvas); 
} 
/** 
* 繪制未選中圖標(biāo) 
* @param canvas 
* @param alpha 
*/ 
private void drawSourceBitmap(Canvas canvas, int alpha) { 
mPaint.setAntiAlias(true); 
mPaint.setDither(true); 
mPaint.setAlpha(255 - alpha); 
canvas.drawBitmap(mUnselectedIconBitmap, null, mIconRect, mPaint); 
} 
/** 
* 繪制選中圖標(biāo) 
* @param canvas 
* @param alpha 
*/ 
private void drawTargetBitmap(Canvas canvas, int alpha) { 
mPaint.setAntiAlias(true); 
mPaint.setDither(true); 
mPaint.setAlpha(alpha); 
canvas.drawBitmap(mSelectedIconBitmap, null, mIconRect, mPaint); 
} 
/** 
* 畫未選中文字 
* @param canvas 
* @param alpha 
*/ 
private void drawSourceText(Canvas canvas, int alpha) { 
mTextPaint.setTextSize(mTextSize); 
mTextPaint.setColor(mUnselectedColor); 
mTextPaint.setAlpha(255 - alpha); 
canvas.drawText(mText, mIconRect.left + mIconRect.width() / 2 
- mTextBound.width() / 2, 
mIconRect.bottom + mTextBound.height(), mTextPaint); 
} 
/** 
* 畫選中文字 
* @param canvas 
* @param alpha 
*/ 
private void drawTargetText(Canvas canvas, int alpha) { 
mTextPaint.setColor(mSelectedColor); 
mTextPaint.setAlpha(alpha); 
canvas.drawText(mText, mIconRect.left + mIconRect.width() / 2 
- mTextBound.width() / 2, 
mIconRect.bottom + mTextBound.height(), mTextPaint); 
}

代碼中的mAlpha是ViewPager滾動的百分比,然后分別繪制選中以及未選中的圖標(biāo)和文本,但是繪制的時(shí)候設(shè)置的透明度不同,這樣就會有一個(gè)漸變的效果。

在ViewPager單張圖片圖片的時(shí),我們再把效果圖拿過來觀察下:

private void setupTargetBitmap(int alpha) { 
mBitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Config.ARGB_8888); 
mCanvas = new Canvas(mBitmap); 
mPaint = new Paint(); 
mPaint.setColor(mSelectedColor); 
mPaint.setAntiAlias(true); 
mPaint.setDither(true); 
mPaint.setAlpha(alpha); 
mCanvas.drawRect(mIconRect, mPaint); 
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); 
mPaint.setAlpha(255); 
mCanvas.drawBitmap(mIconBitmap, null, mIconRect, mPaint); 
} 
private void drawSourceText(Canvas canvas, int alpha) { 
mTextPaint.setTextSize(mTextSize); 
mTextPaint.setColor(mUnselectedColor); 
mTextPaint.setAlpha(255 - alpha); 
canvas.drawText(mText, mIconRect.left + mIconRect.width() / 2 
- mTextBound.width() / 2, 
mIconRect.bottom + mTextBound.height(), mTextPaint); 
} 
private void drawTargetText(Canvas canvas, int alpha) { 
mTextPaint.setColor(mSelectedColor); 
mTextPaint.setAlpha(alpha); 
canvas.drawText(mText, mIconRect.left + mIconRect.width() / 2 
- mTextBound.width() / 2, 
mIconRect.bottom + mTextBound.height(), mTextPaint); 
}

繪制的過程大致與兩張圖片相同,不同點(diǎn)就是在繪制圖片的時(shí)候Paint設(shè)置 Xfermode,來控制顏色的漸變。

OK,Tab條目的自定義View搞定之后剩下的就簡單多了。

六、定義屬性

接下來就是封裝繼承自LinearLayout的整體控件,先來定義下屬性。

可以看到tabIcons為單張圖片漸變效果特殊的,tabSelectedIcons和tabUnselectedIcon為兩張圖標(biāo)切換效果特殊的。

七、 控件編寫

由于三中樣式有公共的部分,我們進(jìn)行積累抽取。類圖結(jié)構(gòu)如下:

1. 構(gòu)造函數(shù)初始化自定義屬性

在TabIndicatorBase中初始化自定義屬性

private void init(Context context, AttributeSet attrs) { 
setOrientation(LinearLayout.HORIZONTAL); 
setGravity(Gravity.CENTER); 
//Load defaults from resources 
final Resources res = getResources(); 
final int defaultSelectedColor = res.getColor(R.color.default_tab_view_selected_color); 
final int defaultUnselectedColor = res.getColor(R.color.default_tab_view_unselected_color); 
final float defaultTextSize = res.getDimension(R.dimen.default_tab_view_text_size); 
final float defaultTabPadding = res.getDimension(R.dimen.default_tab_view_padding); 
final float defaultIndicatorSize = res.getDimension(R.dimen.default_tab_view_indicator_size); 
// Styleables from XML 
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TabIndicator); 
// 讀取布局中,各個(gè)tab使用的文字 
if (a.hasValue(R.styleable.TabIndicator_tabLabels)) { 
mLabels = a.getTextArray(R.styleable.TabIndicator_tabLabels); 
} 
mSelectedColor = a.getColor(R.styleable.TabIndicator_tabSelectedColor, defaultSelectedColor); 
mUnselectedColor = a.getColor(R.styleable.TabIndicator_tabUnselectedColor, defaultUnselectedColor); 
mTextSize = (int) a.getDimension(R.styleable.TabIndicator_tabTextSize, defaultTextSize); 
mIndicatorSize = (int) a.getDimension(R.styleable.TabIndicator_TabIndicatorSize, defaultIndicatorSize); 
mTabPadding = (int) a.getDimension(R.styleable.TabIndicator_tabItemPadding, defaultTabPadding); 
handleStyledAttributes(a); 
a.recycle(); 
initView(); 
}

由于有些屬性不是公共的,這里定義handleStyleAttributes(a)的抽象方法,在子類中去實(shí)現(xiàn)。

2. 初始化View

/** 
* 初始化控件 
*/ 
private void initView() { 
LayoutParams params = new LayoutParams(0, LayoutParams.MATCH_PARENT, 1); 
params.gravity = Gravity.CENTER; 
int size = getTabSize(); 
for (int i = 0; i < size; i++) { 
final int index = i; 
T tabItemView = createTabView(); 
tabItemView.setPadding(mTabPadding, mTabPadding, mTabPadding, mTabPadding); 
// 圖標(biāo)及文字 
if(null != mLabels) { 
tabItemView.setText(mLabels[index]); 
tabItemView.setTextSize(mTextSize); 
} 
tabItemView.setSelectedColor(mSelectedColor); 
tabItemView.setUnselectedColor(mUnselectedColor); 
tabItemView.setIndicatorSize(mIndicatorSize); 
setProperties(tabItemView, i); 
this.addView(tabItemView, params); 
tabItemView.setTag(index); // CheckedTextView設(shè)置索引作為tag,以便后續(xù)更改顏色、圖片等 
mCheckedList.add(tabItemView); // 將CheckedTextView添加到list中,便于操作 
tabItemView.setOnClickListener(new OnClickListener() 
@Override 
public void onClick(View v) { 
setTabsDisplay(index); // 設(shè)置底部圖片和文字的顯示 
if (null != mTabListener) { 
mTabListener.onTabSelected(index); // tab項(xiàng)被選中的回調(diào)事件 
} 
} 
}); 
// 初始化 底部菜單選中狀態(tài),默認(rèn)第一個(gè)選中 
if (i == 0) { 
tabItemView.setSelected(true); 
} else { 
tabItemView.setSelected(false); 
} 
} 
}

生成Tab條目以及設(shè)置特殊的屬性都通過抽象方法的方式交給子類去完成。

/** 
* 生成TabView 
* @return 
*/ 
protected abstract T createTabView(); 
/** 
* 設(shè)置特殊屬性 
* @param t 
*/ 
protected abstract void setProperties(T t, int index); 

3. 子類實(shí)現(xiàn)

由于這里都比較簡單,我們選取其中一個(gè)簡單的雙圖標(biāo)圖片來說明:

@Override 
protected void handleStyledAttributes(TypedArray a) { 
// 讀取布局中,各個(gè)tab使用的圖標(biāo) 
int selectedIconsResId = a.getResourceId(R.styleable.TabIndicator_tabSelectedIcons, 0); 
TypedArray ta = getContext().getResources().obtainTypedArray(selectedIconsResId); 
int len = ta.length(); 
mSelectedDrawableIds = new int[len]; 
for(int i = 0; i < len; i++) { 
mSelectedDrawableIds[i] = ta.getResourceId(i, 0); 
} 
int unselectedIconsResId = a.getResourceId(R.styleable.TabIndicator_tabUnselectedIcons, 0); 
ta = getContext().getResources().obtainTypedArray(unselectedIconsResId); 
len = ta.length(); 
mUnselectedDrawableIds = new int[len]; 
for(int i = 0; i < len; i++) { 
mUnselectedDrawableIds[i] = ta.getResourceId(i, 0); 
} 
ta.recycle(); 
}

這里讀取了xml中配置的選中及未選中圖標(biāo)

生成TabView

@Override 
protected TabView createTabView() { 
return new TabView(getContext()); 
} 

設(shè)置特殊屬性

@Override 
protected void setProperties(TabView tabView, int index) { 
tabView.setSelectedIcon(mSelectedDrawableIds[index]); 
tabView.setUnselectedIcon(mUnselectedDrawableIds[index]); 
} 

獲取條目個(gè)數(shù)

@Override 
protected int getTabSize() { 
return mSelectedDrawableIds.length; 
}

八、源碼及示例

給大家提供一個(gè)github的地址: Android-TabIndicator
另外,歡迎 star or f**k me on github!

九、一行引入庫

如果您的項(xiàng)目使用 Gradle 構(gòu)建, 只需要在您的build.gradle文件添加下面一行到 dependencies :
compile 'com.kevin:tabindicator:1.0.1'

關(guān)于小編給大家分享的Android 底部導(dǎo)航控件實(shí)例代碼就到此結(jié)束了,希望對大家有所幫助!

相關(guān)文章

  • Android中使用socket通信實(shí)現(xiàn)消息推送的方法詳解

    Android中使用socket通信實(shí)現(xiàn)消息推送的方法詳解

    這篇文章主要介紹了Android中使用socket通信實(shí)現(xiàn)消息推送的方法,文中舉了一個(gè)消息發(fā)送端和一個(gè)消息接收端以及服務(wù)器端的例子來說明原理并且展示了客戶端的實(shí)現(xiàn),需要的朋友可以參考下
    2016-04-04
  • 搭建Android上的服務(wù)器 “實(shí)現(xiàn)隔空取物”的方法

    搭建Android上的服務(wù)器 “實(shí)現(xiàn)隔空取物”的方法

    本篇文章主要介紹了搭建Android上的服務(wù)器 “實(shí)現(xiàn)隔空取物”的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-01-01
  • Android中socket通信的簡單實(shí)現(xiàn)

    Android中socket通信的簡單實(shí)現(xiàn)

    這篇文章主要為大家詳細(xì)介紹了Android中socket通信的簡單實(shí)現(xiàn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-04-04
  • Android 安全加密:對稱加密詳解

    Android 安全加密:對稱加密詳解

    本文主要介紹Android 安全加密對稱加密,這里整理了詳細(xì)的資料及介紹凱撒密碼和對稱密碼的資料,有興趣的小伙伴可以參考下
    2016-09-09
  • Android中persistent屬性用法詳解

    Android中persistent屬性用法詳解

    這篇文章主要介紹了Android中persistent屬性用法,詳細(xì)分析了persistent屬性的功能及相關(guān)用法,需要的朋友可以參考下
    2016-06-06
  • Android開發(fā)中超好用的正則表達(dá)式工具類RegexUtil完整實(shí)例

    Android開發(fā)中超好用的正則表達(dá)式工具類RegexUtil完整實(shí)例

    這篇文章主要介紹了Android開發(fā)中超好用的正則表達(dá)式工具類RegexUtil,結(jié)合完整實(shí)例形式分析了Android正則表達(dá)式常見操作技巧,包括針對證件號、銀行賬號、手機(jī)號、郵編等的正則判斷相關(guān)操作技巧,需要的朋友可以參考下
    2017-11-11
  • Android仿微信實(shí)現(xiàn)下拉列表

    Android仿微信實(shí)現(xiàn)下拉列表

    這篇文章主要介紹了Android仿微信實(shí)現(xiàn)下拉列表的相關(guān)資料,需要的朋友可以參考下
    2015-12-12
  • Android SQLite數(shù)據(jù)庫加密的操作方法

    Android SQLite數(shù)據(jù)庫加密的操作方法

    因?yàn)锳ndroid自帶的SQLite數(shù)據(jù)庫本身是沒有實(shí)現(xiàn)加密的,那我們?nèi)绾螌?shí)現(xiàn)對數(shù)據(jù)庫的加密呢?今天通過本文給大家介紹下Android SQLite數(shù)據(jù)庫加密的操作方法,一起看看吧
    2021-09-09
  • Andriod 獲取電池的信息實(shí)例代碼

    Andriod 獲取電池的信息實(shí)例代碼

    通過本段實(shí)例代碼給大家介紹Andriod 獲取電池的信息的相關(guān)知識,對android獲取電池信息相關(guān)知識感興趣的朋友一起學(xué)習(xí)吧
    2016-03-03
  • Android音樂播放器制作 加入控制臺(三)

    Android音樂播放器制作 加入控制臺(三)

    這篇文章主要為大家詳細(xì)介紹了Android音樂播放器的制作方法,如何加入控制臺,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-02-02

最新評論

邳州市| 忻城县| 浦城县| 化德县| 苍南县| 安宁市| 云安县| 措美县| 合江县| 阿城市| 遂宁市| 临清市| 循化| 余干县| 林甸县| 来宾市| 穆棱市| 陆丰市| 奈曼旗| 文昌市| 衡东县| 水富县| 张北县| 商河县| 鄄城县| 合山市| 兰考县| 天台县| 铜陵市| 沁水县| 莎车县| 治多县| 沧源| 新晃| 东乌珠穆沁旗| 西藏| 锦州市| 麦盖提县| 枣阳市| 胶南市| 孟津县|