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

思路分析:

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实现字母导航栏的代码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

时间: 2024-10-27 15:49:37

Android自定义View实现字母导航栏的代码的相关文章

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

思路分析: 1.自定义View实现字母导航栏 2.ListView实现联系人列表 3.字母导航栏滑动事件处理 4.字母导航栏与中间字母的联动 5.字母导航栏与ListView的联动 效果图: 首先,我们先甩出主布局文件,方便后面代码的说明 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/re

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

很多的Android入门程序猿来说对于Android自定义View,可能都是比较恐惧的,但是这又是高手进阶的必经之路,所有准备在自定义View上面花一些功夫,多写一些文章. 思路分析: 1.自定义View实现字母导航栏 2.ListView实现联系人列表 3.字母导航栏滑动事件处理 4.字母导航栏与中间字母的联动 5.字母导航栏与ListView的联动 效果图: 首先,我们先甩出主布局文件,方便后面代码的说明 <!--?xml version="1.0" encoding=&qu

Android design包自定义tablayout的底部导航栏的实现方法

以前做项目大多用的radiobutton,今天用tablayout来做一个tab切换页面的的效果. 实现的效果就是类似QQ.微信的页面间(也就是Fragment间)的切换.如图: 布局只要一个tablayout <android.support.design.widget.TabLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:id=&

界面-Android自定义View画笔颜色改变问题(画笔颜色改变了,但是实际上ABCD这些字母的颜色没变)

问题描述 Android自定义View画笔颜色改变问题(画笔颜色改变了,但是实际上ABCD这些字母的颜色没变) package com.eage.tbw.view; import com.eage.tbw.R; import com.eage.tbw.R.color; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import andro

Android自定义View之组合控件实现类似电商app顶部栏_Android

本文实例为大家分享了Android自定义View之组合控件,仿电商app顶部栏的相关代码,供大家参考,具体内容如下 效果图: 分析:左右两边可以是TextView和Button,设置drawableTop即可,中间的看着像是EditText,但是用过淘宝天猫等类似app的话会发现点击搜索不是在当前Activit进行搜索的,是跳转到另外的页面进行的,所以用TextView然后设置背景即可. 实现流程 参数列表: 设置属性文件:values下建立attrs.xml文件,添加需要自定义的属性. <?x

Android自定义View之组合控件实现类似电商app顶部栏

本文实例为大家分享了Android自定义View之组合控件,仿电商app顶部栏的相关代码,供大家参考,具体内容如下 效果图: 分析:左右两边可以是TextView和Button,设置drawableTop即可,中间的看着像是EditText,但是用过淘宝天猫等类似app的话会发现点击搜索不是在当前Activit进行搜索的,是跳转到另外的页面进行的,所以用TextView然后设置背景即可. 实现流程 参数列表: 设置属性文件:values下建立attrs.xml文件,添加需要自定义的属性. <?x

Android仿网易客户端顶部导航栏效果_Android

最近刚写了一个网易客户端首页导航条的动画效果,现在分享出来给大家学习学习.我说一下这个效果的核心原理.下面是效果图:          首先是布局,这个布局是我从网易客户端反编译后弄来的.大家看后应该明白,布局文件如下: <FrameLayout android:id="@id/column_navi" android:layout_width="fill_parent" android:layout_height="wrap_content&quo

Android程序开发之Fragment实现底部导航栏实例代码_Android

流行的应用的导航一般分为两种,一种是底部导航,一种是侧边栏. 说明 IDE:AS,Android studio; 模拟器:genymotion; 实现的效果,见下图. 具体实现 为了讲明白这个实现过程,我们贴出来的代码多一写,这样更方便理解 [最后还会放出完整的代码实现] .看上图的界面做的比较粗糙,但实现过程的骨架都具有了,想要更完美的设计,之后自行完善吧 ^0^. 布局 通过观察上述效果图,发现任意一个选项页面都有三部分组成: 顶部去除ActionBar后的标题栏: 中间一个Fragment

Android实现沉浸式导航栏实例代码_Android

废话不多说了,直接给大家贴代码了,具体代码如下所示: private SystemBarTintManager tintManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // getWindow().addFlags(WindowManager.Layo