当前位置: 移动技术网 > IT编程>移动开发>Android > Android自定义View实现字母导航栏的代码

Android自定义View实现字母导航栏的代码

2019年07月24日  | 移动技术网IT编程  | 我要评论

酒杯架模型,华山儿童公园,浙江中都集团

思路分析:

1、自定义view实现字母导航栏

2、listview实现联系人列表

3、字母导航栏滑动事件处理

4、字母导航栏与中间字母的联动

5、字母导航栏与listview的联动

效果图:

首先,我们先甩出主布局文件,方便后面代码的说明

<?xml version="1.0" encoding="utf-8"?> 
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:layout_width="match_parent" 
android:layout_height="match_parent" 
android:orientation="vertical"> 
<edittext 
android:layout_width="match_parent" 
android:layout_height="wrap_content" 
android:background="@drawable/search_border" 
android:drawableleft="@android:drawable/ic_menu_search" 
android:padding="8dp" /> 
<relativelayout 
android:layout_width="match_parent" 
android:layout_height="match_parent"> 
<listview 
android:id="@+id/lv" 
android:layout_width="match_parent" 
android:layout_height="match_parent" 
android:divider="@null" /> 
<textview 
android:id="@+id/tv" 
android:layout_width="50dp" 
android:layout_height="50dp" 
android:layout_centerinparent="true" 
android:background="#888888" 
android:gravity="center" 
android:textcolor="#000000" 
android:textsize="18dp" 
android:visibility="gone" /> 
<com.handsome.tulin.view.navview 
android:id="@+id/nv" 
android:layout_width="20dp" 
android:layout_height="match_parent" 
android:layout_alignparentright="true" 
android:layout_margin="16dp" /> 
</relativelayout> 
</linearlayout>

步骤一:分析自定义字母导航栏

思路分析:

1、我们在使用的时候把宽设置为20dp,高设置为填充父控件,所以这里获取的宽度为20dp

2、通过循环,画出竖直的字母,每画一次得重新设置一下颜色,因为我们需要一个选中的字母颜色和默认不一样

public class navview extends view { 
private paint textpaint = new paint(); 
private string[] s = new string[]{ 
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", 
"l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", 
"w", "x", "y", "z", "#"}; 
//鼠标点击、滑动时选择的字母 
private int choose = -1; 
//中间的文本 
private textview tv; 
public navview(context context, attributeset attrs) { 
super(context, attrs); 
} 
public navview(context context) { 
super(context); 
} 
public navview(context context, attributeset attrs, int defstyleattr) { 
super(context, attrs, defstyleattr); 
} 
private void initpaint() { 
textpaint.settextsize(20); 
textpaint.setantialias(true); 
textpaint.setcolor(color.black); 
} 
@override 
protected void ondraw(canvas canvas) { 
super.ondraw(canvas); 
//画字母 
drawtext(canvas); 
} 
/** 
* 画字母 
* 
* @param canvas 
*/ 
private void drawtext(canvas canvas) { 
//获取view的宽高 
int width = getwidth(); 
int height = getheight(); 
//获取每个字母的高度 
int singleheight = height / s.length; 
//画字母 
for (int i = 0; i < s.length; i++) { 
//画笔默认颜色 
initpaint(); 
//高亮字母颜色 
if (choose == i) { 
textpaint.setcolor(color.red); 
} 
//计算每个字母的坐标 
float x = (width - textpaint.measuretext(s[i])) / 2; 
float y = (i + 1) * singleheight; 
canvas.drawtext(s[i], x, y, textpaint); 
//重置颜色 
textpaint.reset(); 
} 
} 
}

步骤二:listview实现联系人列表

思路分析:

1、在主activity中,定义一个数据数组,使用工具类获取数组的第一个字母,使用collections根据第一个字母进行排序,由于工具类有点长,就不贴出来了。

2、创建一个listview子布局,创建一个adapter进行填充。

主布局:

public class mainactivity extends appcompatactivity { 
private textview tv; 
private listview lv; 
private navview nv; 
private list<user> list; 
private useradapter adapter; 
private string[] name = new string[]{ 
"潘粤明", "戴军", "薛之谦", "蓝雨", "任泉", "张杰", "秦俊杰", 
"陈坤", "田亮", "夏雨", "保剑锋", "陆毅", "乔振宇", "吉杰", "郭敬明", "巫迪文", "欢子", "井柏然", 
"左小祖咒", "段奕宏", "毛宁", "樊凡", "汤潮", "山野", "陈龙", "侯勇", "俞思远", "冯绍峰", "崔健", 
"杜淳", "张翰", "彭坦", "柏栩栩", "蒲巴甲", "凌潇肃", "毛方圆", "武艺", "耿乐", "钱泳辰"}; 
@override 
protected void oncreate(bundle savedinstancestate) { 
super.oncreate(savedinstancestate); 
setcontentview(r.layout.activity_main); 
initview(); 
initdata(); 
} 
private void initview() { 
tv = (textview) findviewbyid(r.id.tv); 
lv = (listview) findviewbyid(r.id.lv); 
nv = (navview) findviewbyid(r.id.nv); 
nv.settextview(tv); 
} 
private void initdata() { 
//初始化数据 
list = new arraylist<>(); 
for (int i = 0; i < name.length; i++) { 
list.add(new user(name[i], characterutils.getfirstspell(name[i]).touppercase())); 
} 
//将拼音排序 
collections.sort(list, new comparator<user>() { 
@override 
public int compare(user lhs, user rhs) { 
return lhs.getfirstcharacter().compareto(rhs.getfirstcharacter()); 
} 
}); 
//填充listview 
adapter = new useradapter(this, list); 
lv.setadapter(adapter); 
} 
}

listview子布局:

<?xml version="1.0" encoding="utf-8"?> 
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:layout_width="match_parent" 
android:layout_height="match_parent" 
android:background="#ffffff" 
android:orientation="vertical"> 
<textview 
android:id="@+id/tv_firstcharacter" 
android:layout_width="match_parent" 
android:layout_height="wrap_content" 
android:background="#dbdbda" 
android:padding="8dp" 
android:text="a" 
android:textcolor="#000000" 
android:textsize="14dp" /> 
<textview 
android:id="@+id/tv_name" 
android:layout_width="match_parent" 
android:layout_height="wrap_content" 
android:background="#ffffff" 
android:padding="8dp" 
android:text="张栋梁" 
android:textcolor="#2196f3" 
android:textsize="14dp" /> 
</linearlayout>

adapter:

public class useradapter extends baseadapter { 
private list<user> list; 
private user user; 
private layoutinflater minflater; 
private context context; 
public useradapter(context context, list<user> list) { 
this.list = list; 
minflater = layoutinflater.from(context); 
this.context = context; 
} 
@override 
public int getcount() { 
return list.size(); 
} 
@override 
public object getitem(int position) { 
return list.get(position); 
} 
@override 
public long getitemid(int position) { 
return position; 
} 
@override 
public view getview(int position, view convertview, viewgroup parent) { 
if (convertview == null) { 
convertview = minflater.inflate(r.layout.adapter_user, null); 
} 
viewholder holder = getviewholder(convertview); 
user = list.get(position); 
if (position == 0) { 
//第一个数据要显示字母和姓名 
holder.tv_firstcharacter.setvisibility(view.visible); 
holder.tv_firstcharacter.settext(user.getfirstcharacter()); 
holder.tv_name.settext(user.getusername()); 
} else { 
//其他数据判断是否为同个字母,这里使用ascii码比较大小 
if (characterutils.getcnascii(list.get(position - 1).getfirstcharacter().charat(0)) < 
characterutils.getcnascii(user.getfirstcharacter().charat(0))) { 
//后面字母的值大于前面字母的值,需要显示字母 
holder.tv_firstcharacter.setvisibility(view.visible); 
holder.tv_firstcharacter.settext(user.getfirstcharacter()); 
holder.tv_name.settext(user.getusername()); 
} else { 
//后面字母的值等于前面字母的值,不显示字母 
holder.tv_firstcharacter.setvisibility(view.gone); 
holder.tv_name.settext(user.getusername()); 
} 
} 
return convertview; 
} 
/** 
* 获得控件管理对象 
* 
* @param view 
* @return 
*/ 
private viewholder getviewholder(view view) { 
viewholder holder = (viewholder) view.gettag(); 
if (holder == null) { 
holder = new viewholder(view); 
view.settag(holder); 
} 
return holder; 
} 
/** 
* 控件管理类 
*/ 
private class viewholder { 
private textview tv_firstcharacter, tv_name; 
viewholder(view view) { 
tv_firstcharacter = (textview) view.findviewbyid(r.id.tv_firstcharacter); 
tv_name = (textview) view.findviewbyid(r.id.tv_name); 
} 
} 
/** 
* 通过字符查找位置 
* 
* @param s 
* @return 
*/ 
public int getselectposition(string s) { 
for (int i = 0; i < getcount(); i++) { 
string firchar = list.get(i).getfirstcharacter(); 
if (firchar.equals(s)) { 
return i; 
} 
} 
return -1; 
} 
}

步骤三:字母导航栏滑动事件处理、字母导航栏与中间字母的联动

思路分析:

1、在自定义view中重写dispatchtouchevent处理滑动事件,最后返回true。

2、在主activity传进来一个textview,在我们滑动的时候设置text,松开的时候消失text。设置text的时候需要计算text的位置,并且滑过多的话会出现数组越界的问题,所以我们在里面处理数组越界问题。

3、最后,提供一个接口,记录我们滑到的字母,为了后面可以和listview联动。

@override 
public boolean dispatchtouchevent(motionevent event) { 
//计算选中字母 
int index = (int) (event.gety() / getheight() * s.length); 
//防止脚标越界 
if (index >= s.length) { 
index = s.length - 1; 
} else if (index < 0) { 
index = 0; 
} 
switch (event.getaction()) { 
case motionevent.action_down: 
case motionevent.action_move: 
setbackgroundcolor(color.gray); 
//选中字母高亮 
choose = index; 
//出现中间文字 
tv.setvisibility(visible); 
tv.settext(s[choose]); 
//调用listview连动接口 
if (listener != null) { 
listener.touchcharacterlistener(s[choose]); 
} 
//重绘 
invalidate(); 
break; 
default: 
setbackgroundcolor(color.transparent); 
//取消选中字母高亮 
choose = -1; 
//隐藏中间文字 
tv.setvisibility(gone); 
//重绘 
invalidate(); 
break; 
} 
return true; 
} 
public ontouchcharacterlistener listener; 
public interface ontouchcharacterlistener { 
void touchcharacterlistener(string s); 
} 
public void setlistener(ontouchcharacterlistener listener) { 
this.listener = listener; 
} 
/** 
* 传进来一个textview 
* 
* @param tv 
*/ 
public void settextview(textview tv) { 
this.tv = tv; 
}

步骤四:字母导航栏和listview的联动

思路分析:

1、我们已经通过接口传递过去了一个选择的字母,和在adapter写好了根据字母查询position的方法,这个时候只要主activity对自定义view设置监听,判断即可。

//listview连动接口 
nv.setlistener(new navview.ontouchcharacterlistener() { 
@override 
public void touchcharacterlistener(string s) { 
int position = adapter.getselectposition(s); 
if (position != -1) { 
lv.setselection(position); 
} 
} 
});

以上所述是小编给大家介绍的android自定义view实现字母导航栏的代码,希望对大家有所帮助

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网