底部导航php代码,Android_Android 底部导航控件实例代码,一、先给大家展示下最终效果 - phpStudy...

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) {

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;

// 设置icon的绘制范围

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

// 设置指示点的范围

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);

}

在以上代码中可以看到,测量文字的高度,用控件的高度减去文字的高度和控件的宽度对比,取较小的为图片的大小,也就是设置的图片要为正方形,否则会产生变形。

看下普通两张图片切换的TabView的绘制:

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

setupTargetBitmap(canvas);

drawIndicator(canvas);

if(null != mText) {

drawTargetText(canvas);

}

}

/**

* 绘制图标图片

* @param canvas

*/

private void setupTargetBitmap(Canvas canvas) {

canvas.drawBitmap(isSelected ? mSelectedIconBitmap : mUnselectedIconBitmap, null, mIconRect, null);

}

/**

* 绘制指示点

* @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);

}

可以看到非常的简单,就是绘制图标图片以及绘制指示点,在绘制图标图片时判断当前条目是否在选中状态,根据是否选中来绘制不同的图片,在绘制指示点的时候首先判断下是否设置了显示指示点。如果有底部文字,那么久绘制底部文字。

在ViewPager两张图片图片的时,我们再把效果图拿过来观察下:

这里有两种模式,即随着ViewPager的滚动图标渐变及普通变化。OK,了解之后我们就能很轻松的来编写它的绘制了,可以通过绘制两张图片,但是在绘制的时候控制它的透明度就可以啦,是不是也很简单。

@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);

}

/**

* 绘制未选中图标

* @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);

}

/**

* 绘制选中图标

* @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滚动的百分比,然后分别绘制选中以及未选中的图标和文本,但是绘制的时候设置的透明度不同,这样就会有一个渐变的效果。

在ViewPager单张图片图片的时,我们再把效果图拿过来观察下:

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);

}

绘制的过程大致与两张图片相同,不同点就是在绘制图片的时候Paint设置 Xfermode,来控制颜色的渐变。

OK,Tab条目的自定义View搞定之后剩下的就简单多了。

六、定义属性

接下来就是封装继承自LinearLayout的整体控件,先来定义下属性。

可以看到tabIcons为单张图片渐变效果特殊的,tabSelectedIcons和tabUnselectedIcon为两张图标切换效果特殊的。

七、 控件编写

由于三中样式有公共的部分,我们进行积累抽取。类图结构如下:

1. 构造函数初始化自定义属性

在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);

// 读取布局中,各个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)的抽象方法,在子类中去实现。

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);

// 图标及文字

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设置索引作为tag,以便后续更改颜色、图片等

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

tabItemView.setOnClickListener(new OnClickListener()

@Override

public void onClick(View v) {

setTabsDisplay(index); // 设置底部图片和文字的显示

if (null != mTabListener) {

mTabListener.onTabSelected(index); // tab项被选中的回调事件

}

}

});

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

if (i == 0) {

tabItemView.setSelected(true);

} else {

tabItemView.setSelected(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 = 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中配置的选中及未选中图标

生成TabView

@Override

protected TabView createTabView() {

return new TabView(getContext());

}

设置特殊属性

@Override

protected void setProperties(TabView tabView, int index) {

tabView.setSelectedIcon(mSelectedDrawableIds[index]);

tabView.setUnselectedIcon(mUnselectedDrawableIds[index]);

}

获取条目个数

@Override

protected int getTabSize() {

return mSelectedDrawableIds.length;

}

八、源码及示例

给大家提供一个github的地址: Android-TabIndicator

另外,欢迎 star or f**k me on github!

九、一行引入库

如果您的项目使用 Gradle 构建, 只需要在您的build.gradle文件添加下面一行到 dependencies :

compile 'com.kevin:tabindicator:1.0.1'

关于小编给大家分享的Android 底部导航控件实例代码就到此结束了,希望对大家有所帮助!相关阅读:

Java Socket编程实例(四)- NIO TCP实践

Android开发中遇到端口号占用问题解决方法

php使用curl出现Expect:100-continue解决方法

JSP运行原理和九大隐式对象说明

C++二进制翻转实例分析

win10正式版开机登录密码如何正确取消?

基于promise.js实现nodejs的promises库

node.js中的path.join方法使用说明

简介JavaScript中的getUTCFullYear()方法的使用

Android事件传递机制

Win10系统中怎么使用右键快速加密文件?

在IOS中为什么使用多线程及多线程实现的三种方法

java必学必会之GUI编程

Ubuntu系统下Pure-ftpd的安装及配置教程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值