Android底部导航控件实例代码

Android底部导航控件实例代码

2023年7月15日发(作者:)

Android底部导航控件实例代码⼀、先给⼤家展⽰下最终效果

通过以上可以看到,图⼀是简单的使⽤,图⼆、图三中为结合ViewPager共同使⽤,⽽且都可以随ViewPager的滑动渐变⾊,不同点是图⼆为选中⾮选中两张图⽚,图三的选中⾮选中是⼀张图⽚只是做了颜⾊变化。⼆、 需求我们希望做可以做成这样的,可以在xml布局中引⼊控件并绑定数据,在代码中设置监听回调,并且配置使⽤要⾮常简单!三、需求分析根据我们多年做不明确需求项⽬的经验,以上需求还算明确。那么我们可以采⽤在LinearLayout添加⼦View控件,这个⼦View控件就是我们⾃定义的每个tab条⽬,当然对LinearLayout要设置权重。需求⼤致明确之后就先设计每个条⽬的⼦View控件,这个⼦View控件是⼀个可以切换状态变化的,⼀张、两张都可以切换状态(参考图⼀、图三)。那么这个View要可以设置底部显⽰的⽂字,设置选中时颜⾊、未选中时颜⾊、选中时图⽚、未选中时图⽚、⽂字⼤⼩、设置是否有指⽰点、设置指⽰点⼤⼩、设置指⽰点图⽚等等。四、Tab条⽬接⼝通过需求分析,我们可以定义如下的Tab⼦View操作接⼝:仔细的朋友会发现,为什么在接⼝中没有设置选中图⽚以及设置⾮选中时图⽚,那是因为这个属性不是通⽤的,在不同的实现中再去定义。五、Tab条⽬实现类的继承关系及说明:类图如下所⽰:在TabViewBase中主要的⽅法就是测量,其他的都是对接⼝的简单实现。@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

ure(widthMeasureSpec, heightMeasureSpec);

// 得到绘制icon的宽

int bitmapWidth = (getMeasuredWidth() - getPaddingLeft()

- getPaddingRight(), getMeasuredHeight() - getPaddingTop()

- getPaddingBottom() - ());

int left = getMeasuredWidth() / 2 - bitmapWidth / 2;

int top = (getMeasuredHeight() - ()) / 2 - bitmapWidth / 2;

// 设置icon的绘制范围

mIconRect = new Rect(left, top, left + bitmapWidth, top + bitmapWidth);

// 设置指⽰点的范围

int indicatorRadius = mIndicatorSize / 2;

int tabRealHeight = bitmapWidth + ();

mIndicatorRect = new Rect(left + tabRealHeight* 4/5 - indicatorRadius, top, left+tabRealHeight* 4/5 + indicatorRadius, top + mIndicatorSize);

}

在以上代码中可以看到,测量⽂字的⾼度,⽤控件的⾼度减去⽂字的⾼度和控件的宽度对⽐,取较⼩的为图⽚的⼤⼩,也就是设置的图⽚要为正⽅形,否则会产⽣变形。看下普通两张图⽚切换的TabView的绘制:@Override

protected void onDraw(Canvas canvas) {

(canvas);

setupTargetBitmap(canvas);

drawIndicator(canvas);

if(null != mText) {

drawTargetText(canvas);

}

}

/**

* 绘制图标图⽚

* @param canvas

*/

private void setupTargetBitmap(Canvas canvas) {

tmap(isSelected ? mSelectedIconBitmap : mUnselectedIconBitmap, null, mIconRect, null);

}

/**

* 绘制指⽰点 * @param canvas

*/

protected void drawIndicator(Canvas canvas) {

if(isIndicateDisplay) {

tmap(mIndicatorBitmap, null, mIndicatorRect, null);

}

}

/**

* 绘制⽂字

* @param canvas

*/

protected void drawTargetText(Canvas canvas) {

or(isSelected ? mSelectedColor : mUnselectedColor);

xt(mText, + () / 2

- () / 2,

+ (), mTextPaint);

}可以看到⾮常的简单,就是绘制图标图⽚以及绘制指⽰点,在绘制图标图⽚时判断当前条⽬是否在选中状态,根据是否选中来绘制不同的图⽚,在绘制指⽰点的时候⾸先判断下是否设置了显⽰指⽰点。如果有底部⽂字,那么久绘制底部⽂字。在ViewPager两张图⽚图⽚的时,我们再把效果图拿过来观察下:这⾥有两种模式,即随着ViewPager的滚动图标渐变及普通变化。OK,了解之后我们就能很轻松的来编写它的绘制了,可以通过绘制两张图⽚,但是在绘制的时候控制它的透明度就可以啦,是不是也很简单。@Override

protected void onDraw(Canvas canvas) {

(canvas);

int alpha = (int) ((255 * mAlpha));

drawSourceBitmap(canvas, alpha);

drawTargetBitmap(canvas, alpha);

if(null != mText) {

drawSourceText(canvas, alpha);

drawTargetText(canvas, alpha);

}

drawIndicator(canvas);

}

/**

* 绘制未选中图标

* @param canvas

* @param alpha

*/

private void drawSourceBitmap(Canvas canvas, int alpha) {

iAlias(true);

her(true);

ha(255 - alpha);

tmap(mUnselectedIconBitmap, null, mIconRect, mPaint);

}

/**

* 绘制选中图标

* @param canvas

* @param alpha

*/

private void drawTargetBitmap(Canvas canvas, int alpha) {

iAlias(true);

her(true);

ha(alpha);

tmap(mSelectedIconBitmap, null, mIconRect, mPaint);

}

/**

* 画未选中⽂字

* @param canvas

* @param alpha

*/

private void drawSourceText(Canvas canvas, int alpha) {

tSize(mTextSize);

or(mUnselectedColor);

ha(255 - alpha);

xt(mText, + () / 2

- () / 2,

+ (), mTextPaint);

}

/**

* 画选中⽂字

* @param canvas

* @param alpha

*/ private void drawTargetText(Canvas canvas, int alpha) {

or(mSelectedColor);

ha(alpha);

xt(mText, + () / 2

- () / 2,

+ (), mTextPaint);

}代码中的mAlpha是ViewPager滚动的百分⽐,然后分别绘制选中以及未选中的图标和⽂本,但是绘制的时候设置的透明度不同,这样就会有⼀个渐变的效果。在ViewPager单张图⽚图⽚的时,我们再把效果图拿过来观察下:private void setupTargetBitmap(int alpha) {

mBitmap = Bitmap(getMeasuredWidth(), getMeasuredHeight(), _8888);

mCanvas = new Canvas(mBitmap);

mPaint = new Paint();

or(mSelectedColor);

iAlias(true);

her(true);

ha(alpha);

ct(mIconRect, mPaint);

rmode(new PorterDuffXfermode(_IN));

ha(255);

tmap(mIconBitmap, null, mIconRect, mPaint);

}

private void drawSourceText(Canvas canvas, int alpha) {

tSize(mTextSize);

or(mUnselectedColor);

ha(255 - alpha);

xt(mText, + () / 2

- () / 2,

+ (), mTextPaint);

}

private void drawTargetText(Canvas canvas, int alpha) {

or(mSelectedColor);

ha(alpha);

xt(mText, + () / 2

- () / 2,

+ (), mTextPaint);

}绘制的过程⼤致与两张图⽚相同,不同点就是在绘制图⽚的时候Paint设置 Xfermode,来控制颜⾊的渐变。OK,Tab条⽬的⾃定义View搞定之后剩下的就简单多了。六、定义属性接下来就是封装继承⾃LinearLayout的整体控件,先来定义下属性。可以看到tabIcons为单张图⽚渐变效果特殊的,tabSelectedIcons和tabUnselectedIcon为两张图标切换效果特殊的。七、 控件编写由于三中样式有公共的部分,我们进⾏积累抽取。类图结构如下:1. 构造函数初始化⾃定义属性在TabIndicatorBase中初始化⾃定义属性private void init(Context context, AttributeSet attrs) {

setOrientation(NTAL);

setGravity();

//Load defaults from resources

final Resources res = getResources();

final int defaultSelectedColor = or(t_tab_view_selected_color);

final int defaultUnselectedColor = or(t_tab_view_unselected_color);

final float defaultTextSize = ension(t_tab_view_text_size);

final float defaultTabPadding = ension(t_tab_view_padding);

final float defaultIndicatorSize = ension(t_tab_view_indicator_size);

// Styleables from XML

TypedArray a = StyledAttributes(attrs, icator);

// 读取布局中,各个tab使⽤的⽂字

if (ue(icator_tabLabels)) {

mLabels = tArray(icator_tabLabels);

}

mSelectedColor = or(icator_tabSelectedColor, defaultSelectedColor);

mUnselectedColor = or(icator_tabUnselectedColor, defaultUnselectedColor);

mTextSize = (int) ension(icator_tabTextSize, defaultTextSize);

mIndicatorSize = (int) ension(icator_TabIndicatorSize, defaultIndicatorSize);

mTabPadding = (int) ension(icator_tabItemPadding, defaultTabPadding);

handleStyledAttributes(a);

e();

initView();

}由于有些属性不是公共的,这⾥定义handleStyleAttributes(a)的抽象⽅法,在⼦类中去实现。2. 初始化View/**

* 初始化控件

*/

private void initView() {

LayoutParams params = new LayoutParams(0, _PARENT, 1);

y = ;

int size = getTabSize();

for (int i = 0; i < size; i++) {

final int index = i; T tabItemView = createTabView();

ding(mTabPadding, mTabPadding, mTabPadding, mTabPadding);

// 图标及⽂字

if(null != mLabels) {

t(mLabels[index]);

tSize(mTextSize);

}

ectedColor(mSelectedColor);

electedColor(mUnselectedColor);

icatorSize(mIndicatorSize);

setProperties(tabItemView, i);

w(tabItemView, params);

(index); // CheckedTextView设置索引作为tag,以便后续更改颜⾊、图⽚等

(tabItemView); // 将CheckedTextView添加到list中,便于操作

lickListener(new OnClickListener()

@Override

public void onClick(View v) {

setTabsDisplay(index); // 设置底部图⽚和⽂字的显⽰

if (null != mTabListener) {

elected(index); // tab项被选中的回调事件

}

}

});

// 初始化 底部菜单选中状态,默认第⼀个选中

if (i == 0) {

ected(true);

} else {

ected(false);

}

}

}⽣成Tab条⽬以及设置特殊的属性都通过抽象⽅法的⽅式交给⼦类去完成。/**

* ⽣成TabView

* @return

*/

protected abstract T createTabView();

/**

* 设置特殊属性

* @param t

*/

protected abstract void setProperties(T t, int index);

3. ⼦类实现由于这⾥都⽐较简单,我们选取其中⼀个简单的双图标图⽚来说明:@Override

protected void handleStyledAttributes(TypedArray a) {

// 读取布局中,各个tab使⽤的图标

int selectedIconsResId = ourceId(icator_tabSelectedIcons, 0);

TypedArray ta = getContext().getResources().obtainTypedArray(selectedIconsResId);

int len = ();

mSelectedDrawableIds = new int[len];

for(int i = 0; i < len; i++) {

mSelectedDrawableIds[i] = ourceId(i, 0);

}

int unselectedIconsResId = ourceId(icator_tabUnselectedIcons, 0);

ta = getContext().getResources().obtainTypedArray(unselectedIconsResId);

len = ();

mUnselectedDrawableIds = new int[len];

for(int i = 0; i < len; i++) {

mUnselectedDrawableIds[i] = ourceId(i, 0);

}

e();

}这⾥读取了xml中配置的选中及未选中图标⽣成TabView@Override

protected TabView createTabView() {

return new TabView(getContext());

}

设置特殊属性@Override

protected void setProperties(TabView tabView, int index) {

ectedIcon(mSelectedDrawableIds[index]);

electedIcon(mUnselectedDrawableIds[index]);

}

获取条⽬个数@Override

protected int getTabSize() {

return ;

}⼋、源码及⽰例给⼤家提供⼀个github的地址: Android-TabIndicator另外,欢迎 star or f**k me on github!九、⼀⾏引⼊库如果您的项⽬使⽤ Gradle 构建, 只需要在您的⽂件添加下⾯⼀⾏到 dependencies :compile ':tabindicator:1.0.1'关于⼩编给⼤家分享的Android 底部导航控件实例代码就到此结束了,希望对⼤家有所帮助!

发布者:admin,转转请注明出处:http://www.yc00.com/web/1689428998a246714.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信