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

Android自定义View实现字母导航栏,第1张

概述很多的Android入门程序猿来说对于Android自定义View,可能都是比较恐惧的,但是这又是高手进阶的必经之路,所有准备在自定义View上面花一些功夫,多写一些文章。

很多的AndroID入门程序猿来说对于AndroID自定义view,可能都是比较恐惧的,但是这又是高手进阶的必经之路,所有准备在自定义view上面花一些功夫,多写一些文章。

思路分析:

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

2、ListVIEw实现联系人列表

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

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

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

效果图:

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

<!--?xml version="1.0" enCoding="utf-8"?--><linearlayout androID:layout_height="match_parent" androID:layout_wIDth="match_parent" androID:orIEntation="vertical" xmlns:androID="http://schemas.androID.com/apk/res/androID">  <edittext androID:background="@drawable/search_border" androID:drawableleft="@androID:drawable/ic_menu_search" androID:layout_height="wrap_content" androID:layout_wIDth="match_parent" androID:padding="8dp">  <relativelayout androID:layout_height="match_parent" androID:layout_wIDth="match_parent">  <ListvIEw androID:divIDer="@null" androID:ID="@+ID/lv" androID:layout_height="match_parent" androID:layout_wIDth="match_parent">  <textvIEw androID:background="#888888" androID:gravity="center" androID:ID="@+ID/tv" androID:layout_centerinparent="true" androID:layout_height="50dp" androID:layout_wIDth="50dp" androID:textcolor="#000000" androID:textsize="18dp" androID:visibility="gone">  <com.handsome.tulin.vIEw.navvIEw androID:ID="@+ID/nv" androID:layout_alignparentright="true" androID:layout_height="match_parent" androID:layout_margin="16dp" androID:layout_wIDth="20dp"> </com.handsome.tulin.vIEw.navvIEw></textvIEw></ListvIEw></relativelayout></edittext></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); }}</user></user>

ListVIEw子布局:

<!--?xml version="1.0" enCoding="utf-8"?--><linearlayout androID:background="#ffffff" androID:layout_height="match_parent" androID:layout_wIDth="match_parent" androID:orIEntation="vertical" xmlns:androID="http://schemas.androID.com/apk/res/androID">  <textvIEw androID:background="#DBDBDA" androID:ID="@+ID/tv_firstCharacter" androID:layout_height="wrap_content" androID:layout_wIDth="match_parent" androID:padding="8dp" androID:text="A" androID:textcolor="#000000" androID:textsize="14dp">  <textvIEw androID:background="#ffffff" androID:ID="@+ID/tv_name" androID:layout_height="wrap_content" androID:layout_wIDth="match_parent" androID:padding="8dp" androID:text="张栋梁" androID:textcolor="#2196F3" androID:textsize="14dp"> </textvIEw></textvIEw></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; }}</user></user>

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

思路分析:

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

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

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

@OverrIDepublic 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实现字母导航栏全部内容,希望文章能够帮你解决Android自定义View实现字母导航栏所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1147974.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存