- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Android 底部导航控件实例代码由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
1、先给大家展示下最终效果 。
通过以上可以看到,图一是简单的使用,图2、图三中为结合viewpager共同使用,而且都可以随viewpager的滑动渐变色,不同点是图二为选中非选中两张图片,图三的选中非选中是一张图片只是做了颜色变化.
2、 需求 。
我们希望做可以做成这样的,可以在xml布局中引入控件并绑定数据,在代码中设置监听回调,并且配置使用要非常简单! 。
3、需求分析 。
根据我们多年做不明确需求项目的经验,以上需求还算明确。那么我们可以采用在linearlayout添加子view控件,这个子view控件就是我们自定义的每个tab条目,当然对linearlayout要设置权重.
需求大致明确之后就先设计每个条目的子view控件,这个子view控件是一个可以切换状态变化的,一张、两张都可以切换状态(参考图1、图三)。那么这个view要可以设置底部显示的文字,设置选中时颜色、未选中时颜色、选中时图片、未选中时图片、文字大小、设置是否有指示点、设置指示点大小、设置指示点图片等等.
4、tab条目接口 。
通过需求分析,我们可以定义如下的tab子view操作接口:
仔细的朋友会发现,为什么在接口中没有设置选中图片以及设置非选中时图片,那是因为这个属性不是通用的,在不同的实现中再去定义.
5、tab条目实现 。
类的继承关系及说明:
类图如下所示:
在tabviewbase中主要的方法就是测量,其他的都是对接口的简单实现.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
@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的绘制:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
@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,了解之后我们就能很轻松的来编写它的绘制了,可以通过绘制两张图片,但是在绘制的时候控制它的透明度就可以啦,是不是也很简单.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
@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单张图片图片的时,我们再把效果图拿过来观察下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
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搞定之后剩下的就简单多了.
6、定义属性 。
接下来就是封装继承自linearlayout的整体控件,先来定义下属性.
可以看到tabicons为单张图片渐变效果特殊的,tabselectedicons和tabunselectedicon为两张图标切换效果特殊的.
7、 控件编写 。
由于三中样式有公共的部分,我们进行积累抽取。类图结构如下:
1. 构造函数初始化自定义属性 。
在tabindicatorbase中初始化自定义属性 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
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 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
/**
* 初始化控件
*/
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条目以及设置特殊的属性都通过抽象方法的方式交给子类去完成.
1
2
3
4
5
6
7
8
9
10
|
/**
* 生成tabview
* @return
*/
protected
abstract
t createtabview();
/**
* 设置特殊属性
* @param t
*/
protected
abstract
void
setproperties(t t,
int
index);
|
3. 子类实现 。
由于这里都比较简单,我们选取其中一个简单的双图标图片来说明
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
@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 。
1
2
3
4
|
@override
protected
tabview createtabview() {
return
new
tabview(getcontext());
}
|
设置特殊属性 。
1
2
3
4
5
|
@override
protected
void
setproperties(tabview tabview,
int
index) {
tabview.setselectedicon(mselecteddrawableids[index]);
tabview.setunselectedicon(munselecteddrawableids[index]);
}
|
获取条目个数 。
1
2
3
4
|
@override
protected
int
gettabsize() {
return
mselecteddrawableids.length;
}
|
8、源码及示例 。
给大家提供一个github的地址: android-tabindicator 另外,欢迎 star or f**k me on github.
9、一行引入库 。
如果您的项目使用 gradle 构建, 只需要在您的build.gradle文件添加下面一行到 dependencies : compile 'com.kevin:tabindicator:1.0.1' 。
关于小编给大家分享的android 底部导航控件实例代码就到此结束了,希望对大家有所帮助! 。
最后此篇关于Android 底部导航控件实例代码的文章就讲到这里了,如果你想了解更多关于Android 底部导航控件实例代码的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我尝试理解[c代码 -> 汇编]代码 void node::Check( data & _data1, vector& _data2) { -> push ebp -> mov ebp,esp ->
我需要在当前表单(代码)的上下文中运行文本文件中的代码。其中一项要求是让代码创建新控件并将其添加到当前窗体。 例如,在Form1.cs中: using System.Windows.Forms; ..
我有此 C++ 代码并将其转换为 C# (.net Framework 4) 代码。有没有人给我一些关于 malloc、free 和 sprintf 方法的提示? int monate = ee; d
我的网络服务器代码有问题 #include #include #include #include #include #include #include int
给定以下 html 代码,将列表中的第三个元素(即“美丽”一词)以斜体显示的 CSS 代码是什么?当然,我可以给这个元素一个 id 或一个 class,但 html 代码必须保持不变。谢谢
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
我试图制作一个宏来避免重复代码和注释。 我试过这个: #define GrowOnPage(any Page, any Component) Component.Width := Page.Surfa
我正在尝试将我的旧 C++ 代码“翻译”成头条新闻所暗示的 C# 代码。问题是我是 C# 中的新手,并不是所有的东西都像 C++ 中那样。在 C++ 中这些解决方案运行良好,但在 C# 中只是不能。我
在 Windows 10 上工作,R 语言的格式化程序似乎没有在 Visual Studio Code 中完成它的工作。我试过R support for Visual Studio Code和 R-T
我正在处理一些报告(计数),我必须获取不同参数的计数。非常简单但乏味。 一个参数的示例查询: qCountsEmployee = ( "select count(*) from %s wher
最近几天我尝试从 d00m 调试网络错误。我开始用尽想法/线索,我希望其他 SO 用户拥有可能有用的宝贵经验。我希望能够提供所有相关信息,但我个人无法控制服务器环境。 整个事情始于用户注意到我们应用程
我有一个 app.js 文件,其中包含如下 dojo amd 模式代码: require(["dojo/dom", ..], function(dom){ dom.byId('someId').i
我对“-gencode”语句中的“code=sm_X”选项有点困惑。 一个例子:NVCC 编译器选项有什么作用 -gencode arch=compute_13,code=sm_13 嵌入库中? 只有
我为我的表格使用 X-editable 框架。 但是我有一些问题。 $(document).ready(function() { $('.access').editable({
我一直在通过本教程学习 flask/python http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-wo
我想将 Vim 和 EMACS 用于 CNC、G 代码和 M 代码。 Vim 或 EMACS 是否有任何语法或模式来处理这种类型的代码? 最佳答案 一些快速搜索使我找到了 this vim 和 thi
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 想改进这个问题?更新问题,使其成为 on-topic对于堆栈溢出。 7年前关闭。 Improve this
这个问题在这里已经有了答案: Enabling markdown highlighting in Vim (5 个回答) 6年前关闭。 当我在 Vim 中编辑包含 Markdown 代码的 READM
我正在 Swift3 iOS 中开发视频应用程序。基本上我必须将视频 Assets 和音频与淡入淡出效果合并为一个并将其保存到 iPhone 画廊。为此,我使用以下方法: private func d
pipeline { agent any stages { stage('Build') { steps { e
我是一名优秀的程序员,十分优秀!