之前实习的时候了解到小组内突然有一个需求,就是要把所有的用户列表都像微信和QQ的通讯录一样,很好的展示在界面上,当时因为忙于其他事,一直记住这个需求,但是没想着具体实现,现在闲下来,想到这个需求,看了一天的代码添主要是这篇描述大致了解了一下实现过程,并且将ListView改成RecyclerView来进行实现。现在晚上记录下大致的代码。

字母导航功能实现

  • 0效果图如下:
  • 1分析主界面的组成
  • 1主布局main.xml
  • 2主布局中LettersView的自定义布局
  • 3RecyclerView的使用部分
    • 1实体类Friend
    • 2子布局
    • 3Adapter的编写
  • 4工具类TransToPinYin
  • 5主界面中进行adapter的适配和组件逻辑处理
  • 6项目完善1

0效果图如下:


实现如下:

1分析主界面的组成


界面中主要有三个部分组成。其中View需要自定义去实现。

1主布局main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"android:orientation="vertical"><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="10dp"android:layout_marginTop="5dp"android:layout_marginRight="10dp"android:alpha="0.5"android:background="@color/teal_700"><ImageViewandroid:id="@+id/iv_search"android:layout_width="40dp"android:layout_height="40dp"android:src="@drawable/baseline_search_24"/><EditTextandroid:id="@+id/et_search"android:layout_width="match_parent"android:layout_height="40dp"android:layout_alignParentTop="true"android:layout_marginRight="10dp"android:layout_toRightOf="@+id/iv_search"android:hint="请输入联系人"android:singleLine="true"android:textColor="@color/white"android:textColorHint="@color/white"/><!--刚开始没有输入时这个删除按钮是不应该存在的,只有输入数字之后才可以出现--><ImageViewandroid:id="@+id/iv_delete"android:layout_width="30dp"android:layout_height="30dp"android:layout_alignParentRight="true"android:layout_centerVertical="true"android:layout_marginRight="10dp"android:src="@drawable/baseline_cancel_24"android:visibility="gone"/></RelativeLayout><FrameLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/myRecyclerView"android:layout_width="match_parent"android:layout_height="match_parent"/>
<!--下面主要是为了弹出当前选择的导航栏具体字母在主程序中将选择的导航栏和这个组件绑定即可--><TextViewandroid:id="@+id/tvToast"android:layout_width="100dp"android:layout_height="100dp"android:layout_gravity="center"android:alpha="0.5"android:background="#534848"android:gravity="center"android:text="A"android:textColor="@color/white"android:textSize="25sp"android:visibility="gone"/><!--右侧的导航栏--><com.example.lettersnavigation.LettersViewandroid:id="@+id/mLettersView"android:layout_width="30dp"android:layout_height="match_parent"android:layout_gravity="right"/></FrameLayout></LinearLayout>

2主布局中LettersView的自定义布局

此布局是一个 java文件,直接用的网络上的比如这个篇,主要就是利用画布画出从A-Z和#的绘制

package com.example.lettersnavigation;import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;public class LettersView extends View {//TAGprivate static final String TAG = "LettersView";//字母数组,#代表未知,比如数字开头private String[] strChars = { "#","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 Paint mPaint;//选中字母的下标private int checkIndex;//字母提示的TextView,需要set/get动态设置显示内容private TextView mTextView;//接口回调private OnLettersListViewListener onLettersListViewListener;
//对外的接口,来对当前的位置进行重新赋值public void setCheckIndex(int checkIndex){this.checkIndex=checkIndex;}public LettersView(Context context) {super(context);init();}public LettersView(Context context, AttributeSet attrs) {super(context, attrs);init();}public LettersView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}/*** 初始化*/private void init() {//实例化画笔mPaint = new Paint();//设置stylemPaint.setTypeface(Typeface.DEFAULT_BOLD);//设置抗锯齿mPaint.setAntiAlias(true);}/*** 绘制** @param canvas*/@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);/*** 为了排列26个字母,我们可以用坐标点来计算,X居中,Y为 1/27 的递加计算* 首先获取到我们View的宽高*/int viewWidth = getWidth();int viewHeight = getHeight();//计算一个字母的高度int singleHeight = viewHeight / strChars.length;//循环绘制字母for (int i = 0; i < strChars.length; i++) {//设置选中字母的颜色if (i == checkIndex) {mPaint.setColor(Color.BLUE);mPaint.setTextSize(50);} else {mPaint.setColor(Color.BLACK);//设置字体大小mPaint.setTextSize(40);}/*** 绘制字母* x: (view的宽度 - 文本的宽度)/ 2* y:  singleHeight * x + singleHeight  //单个字母的高度 + 最上面的字幕空白高度*/float lettersX = (viewWidth - mPaint.measureText(strChars[i])) / 2;float lettersY = singleHeight * i + singleHeight;//绘制canvas.drawText(strChars[i], lettersX, lettersY, mPaint);//重绘mPaint.reset();}}public TextView getmTextView() {return mTextView;}public void setmTextView(TextView mTextView) {this.mTextView = mTextView;}/*** 事件分发** @param event* @return*/@Overridepublic boolean dispatchTouchEvent(MotionEvent event) {//判断手势switch (event.getAction()) {case MotionEvent.ACTION_DOWN:case MotionEvent.ACTION_MOVE:setBackgroundResource(R.color.teal_200);//获取点击的Y坐标,以此来判断选中的字母float y = event.getY();//Log.i(TAG, "y:" + y);//第一次被选中的下标int oldCheckIndex = checkIndex;/*** 计算选中的字母* strChars[当前Y / View的高度 * 字母个数]*/int c = (int) (y / getHeight() * strChars.length);//Log.i(TAG, "c:" + c);//判断移动if (oldCheckIndex != c) {//不能越界if (c >= 0 && c < strChars.length) {//效果联动if (onLettersListViewListener != null) {onLettersListViewListener.onLettersListener(strChars[c]);}if (mTextView != null) {mTextView.setVisibility(View.VISIBLE);mTextView.setText(strChars[c]);}}checkIndex = c;invalidate();}break;case MotionEvent.ACTION_UP://设置透明背景setBackgroundResource(android.R.color.transparent);//恢复不选中checkIndex = -1;invalidate();//是否显示if (mTextView != null) {mTextView.setVisibility(View.INVISIBLE);}break;}return true;}/*** 下面两个方法是对接口实现一个set和get的赋值*/public OnLettersListViewListener getOnLettersListViewListener() {return onLettersListViewListener;}public void setOnLettersListViewListener(OnLettersListViewListener onLettersListViewListener) {this.onLettersListViewListener = onLettersListViewListener;}/*** 接口回调/ListView联动*/public interface OnLettersListViewListener {public void onLettersListener(String s);}}

3RecyclerView的使用部分

1实体类Friend
package com.example.lettersnavigation.entityclass Friend(val firstLetter:String,val name:String) {}
2子布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="wrap_content"><TextViewandroid:id="@+id/tvLetters"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="10dp"android:text="A"android:textColor="#C35454"android:textSize="25sp"/><TextViewandroid:id="@+id/tvName"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="5dp"android:text="阿贵"android:textSize="16sp"/><Viewandroid:layout_width="match_parent"android:layout_height="1dp"android:background="@color/black"/></LinearLayout>
3Adapter的编写
package com.example.lettersnavigationimport android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.lettersnavigation.entity.Friendclass FriendRecyclerViewAdapter(var context: Context,var friends:List<Friend>):RecyclerView.Adapter<FriendRecyclerViewAdapter.ViewHolder>() {inner class ViewHolder(view: View):RecyclerView.ViewHolder(view){val tvLetters=view.findViewById<TextView>(R.id.tvLetters)val tvName=view.findViewById<TextView>(R.id.tvName)}
/*在这个方法里面负责子布局的绑定和子布局的按钮监听事件的绑定等*/override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {val view=LayoutInflater.from(parent.context).inflate(R.layout.recycler_item,parent,false)return ViewHolder(view)}override fun onBindViewHolder(holder: ViewHolder, position: Int) {val friend= friends[position]//返回当前朋友姓名的第一个字符val firstChar=friend.firstLetter[0]//根据第一个字符查找出第一个字符属于数据中的第几个val index=getPositionForName(firstChar)if(index==position){holder.tvLetters.visibility=View.VISIBLEholder.tvLetters.text=friend.firstLetter}else{holder.tvLetters.visibility=View.GONE}holder.tvName.text=friend.name}override fun getItemCount(): Int {return friends.size}//遍历所有的姓名,找到当前这个传进来的字符是哪一个fun getPositionForName(firstLetter:Char):Int{for(i in 0 until itemCount){val letter=friends[i].firstLetter//将字符转换成一个大写的val firstChar=letter.uppercase()[0]if(firstChar==firstLetter){//只需要找到第一个匹配的即可,return i}}return -1}}

4工具类TransToPinYin

在通讯录中需要进行排序,而中文进行排序就需要将中文转换成一个拼音,比较第一个字母即可进行排序
所以需要将中文转换成一个拼音。
只是一个工具类,我也没细看,直接就用

package com.example.lettersnavigation.util.utilclass TransToPinYin {private var buffer: StringBuilder? = nullvar resource: String? = nullprivate fun getChsAscii(chs: String): Int {var asc = 0try {val bytes = chs.toByteArray(charset("gb2312"))if (bytes == null || bytes.size > 2 || bytes.size <= 0) { // 错误// logthrow RuntimeException("illegal resource string")// System.out.println("error");}if (bytes.size == 1) { // 英文字符asc = bytes[0].toInt()}if (bytes.size == 2) { // 中文字符val hightByte = 256 + bytes[0]val lowByte = 256 + bytes[1]asc = 256 * hightByte + lowByte - 256 * 256}} catch (e: Exception) {println("ERROR:ChineseSpelling.class-getChsAscii(String chs)"+ e)// e.printStackTrace();}return asc}/*** 转换单个汉字** @param str* @return*/fun convert(str: String): String? {var result: String? = nullval ascii = getChsAscii(str)if (ascii > 0 && ascii < 160) {result = ascii.toChar().toString()} else {for (i in pyvalue.size - 1 downTo 0) {if (pyvalue[i] <= ascii) {result = pystr[i]break}}}return result}/*** 转换一个或多个汉字** @param str* @return*/fun convertAll(str: String): String {var result = ""var strTemp: String? = nullfor (j in 0 until str.length) {strTemp = str.substring(j, j + 1)val ascii = getChsAscii(strTemp)if (ascii > 0 && ascii < 160) {result += ascii.toChar().toString()} else {for (i in pyvalue.size - 1 downTo 0) {if (pyvalue[i] <= ascii) {result += pystr[i]break}}}}return result}fun getSelling(chs: String?): String {var key: Stringvar value: String?buffer = StringBuilder()for (i in 0 until chs!!.length) {key = chs.substring(i, i + 1)if (key.toByteArray().size == 2) {value = convert(key)if (value == null) {value = "unknown"}} else {value = key}buffer!!.append(value)}return buffer.toString()}val spelling: Stringget() = getSelling(resource)companion object {private val pyvalue = intArrayOf(-20319, -20317, -20304, -20295,-20292, -20283, -20265, -20257, -20242, -20230, -20051, -20036,-20032, -20026, -20002, -19990, -19986, -19982, -19976, -19805,-19784, -19775, -19774, -19763, -19756, -19751, -19746, -19741,-19739, -19728, -19725, -19715, -19540, -19531, -19525, -19515,-19500, -19484, -19479, -19467, -19289, -19288, -19281, -19275,-19270, -19263, -19261, -19249, -19243, -19242, -19238, -19235,-19227, -19224, -19218, -19212, -19038, -19023, -19018, -19006,-19003, -18996, -18977, -18961, -18952, -18783, -18774, -18773,-18763, -18756, -18741, -18735, -18731, -18722, -18710, -18697,-18696, -18526, -18518, -18501, -18490, -18478, -18463, -18448,-18447, -18446, -18239, -18237, -18231, -18220, -18211, -18201,-18184, -18183, -18181, -18012, -17997, -17988, -17970, -17964,-17961, -17950, -17947, -17931, -17928, -17922, -17759, -17752,-17733, -17730, -17721, -17703, -17701, -17697, -17692, -17683,-17676, -17496, -17487, -17482, -17468, -17454, -17433, -17427,-17417, -17202, -17185, -16983, -16970, -16942, -16915, -16733,-16708, -16706, -16689, -16664, -16657, -16647, -16474, -16470,-16465, -16459, -16452, -16448, -16433, -16429, -16427, -16423,-16419, -16412, -16407, -16403, -16401, -16393, -16220, -16216,-16212, -16205, -16202, -16187, -16180, -16171, -16169, -16158,-16155, -15959, -15958, -15944, -15933, -15920, -15915, -15903,-15889, -15878, -15707, -15701, -15681, -15667, -15661, -15659,-15652, -15640, -15631, -15625, -15454, -15448, -15436, -15435,-15419, -15416, -15408, -15394, -15385, -15377, -15375, -15369,-15363, -15362, -15183, -15180, -15165, -15158, -15153, -15150,-15149, -15144, -15143, -15141, -15140, -15139, -15128, -15121,-15119, -15117, -15110, -15109, -14941, -14937, -14933, -14930,-14929, -14928, -14926, -14922, -14921, -14914, -14908, -14902,-14894, -14889, -14882, -14873, -14871, -14857, -14678, -14674,-14670, -14668, -14663, -14654, -14645, -14630, -14594, -14429,-14407, -14399, -14384, -14379, -14368, -14355, -14353, -14345,-14170, -14159, -14151, -14149, -14145, -14140, -14137, -14135,-14125, -14123, -14122, -14112, -14109, -14099, -14097, -14094,-14092, -14090, -14087, -14083, -13917, -13914, -13910, -13907,-13906, -13905, -13896, -13894, -13878, -13870, -13859, -13847,-13831, -13658, -13611, -13601, -13406, -13404, -13400, -13398,-13395, -13391, -13387, -13383, -13367, -13359, -13356, -13343,-13340, -13329, -13326, -13318, -13147, -13138, -13120, -13107,-13096, -13095, -13091, -13076, -13068, -13063, -13060, -12888,-12875, -12871, -12860, -12858, -12852, -12849, -12838, -12831,-12829, -12812, -12802, -12607, -12597, -12594, -12585, -12556,-12359, -12346, -12320, -12300, -12120, -12099, -12089, -12074,-12067, -12058, -12039, -11867, -11861, -11847, -11831, -11798,-11781, -11604, -11589, -11536, -11358, -11340, -11339, -11324,-11303, -11097, -11077, -11067, -11055, -11052, -11045, -11041,-11038, -11024, -11020, -11019, -11018, -11014, -10838, -10832,-10815, -10800, -10790, -10780, -10764, -10587, -10544, -10533,-10519, -10331, -10329, -10328, -10322, -10315, -10309, -10307,-10296, -10281, -10274, -10270, -10262, -10260, -10256, -10254)private val pystr = arrayOf("a", "ai", "an", "ang","ao", "ba", "bai", "ban", "bang", "bao", "bei", "ben", "beng","bi", "bian", "biao", "bie", "bin", "bing", "bo", "bu", "ca","cai", "can", "cang", "cao", "ce", "ceng", "cha", "chai", "chan","chang", "chao", "che", "chen", "cheng", "chi", "chong", "chou","chu", "chuai", "chuan", "chuang", "chui", "chun", "chuo", "ci","cong", "cou", "cu", "cuan", "cui", "cun", "cuo", "da", "dai","dan", "dang", "dao", "de", "deng", "di", "dian", "diao", "die","ding", "diu", "dong", "dou", "du", "duan", "dui", "dun", "duo","e", "en", "er", "fa", "fan", "fang", "fei", "fen", "feng", "fo","fou", "fu", "ga", "gai", "gan", "gang", "gao", "ge", "gei", "gen","geng", "gong", "gou", "gu", "gua", "guai", "guan", "guang", "gui","gun", "guo", "ha", "hai", "han", "hang", "hao", "he", "hei","hen", "heng", "hong", "hou", "hu", "hua", "huai", "huan", "huang","hui", "hun", "huo", "ji", "jia", "jian", "jiang", "jiao", "jie","jin", "jing", "jiong", "jiu", "ju", "juan", "jue", "jun", "ka","kai", "kan", "kang", "kao", "ke", "ken", "keng", "kong", "kou","ku", "kua", "kuai", "kuan", "kuang", "kui", "kun", "kuo", "la","lai", "lan", "lang", "lao", "le", "lei", "leng", "li", "lia","lian", "liang", "liao", "lie", "lin", "ling", "liu", "long","lou", "lu", "lv", "luan", "lue", "lun", "luo", "ma", "mai", "man","mang", "mao", "me", "mei", "men", "meng", "mi", "mian", "miao","mie", "min", "ming", "miu", "mo", "mou", "mu", "na", "nai", "nan","nang", "nao", "ne", "nei", "nen", "neng", "ni", "nian", "niang","niao", "nie", "nin", "ning", "niu", "nong", "nu", "nv", "nuan","nue", "nuo", "o", "ou", "pa", "pai", "pan", "pang", "pao", "pei","pen", "peng", "pi", "pian", "piao", "pie", "pin", "ping", "po","pu", "qi", "qia", "qian", "qiang", "qiao", "qie", "qin", "qing","qiong", "qiu", "qu", "quan", "que", "qun", "ran", "rang", "rao","re", "ren", "reng", "ri", "rong", "rou", "ru", "ruan", "rui","run", "ruo", "sa", "sai", "san", "sang", "sao", "se", "sen","seng", "sha", "shai", "shan", "shang", "shao", "she", "shen","sheng", "shi", "shou", "shu", "shua", "shuai", "shuan", "shuang","shui", "shun", "shuo", "si", "song", "sou", "su", "suan", "sui","sun", "suo", "ta", "tai", "tan", "tang", "tao", "te", "teng","ti", "tian", "tiao", "tie", "ting", "tong", "tou", "tu", "tuan","tui", "tun", "tuo", "wa", "wai", "wan", "wang", "wei", "wen","weng", "wo", "wu", "xi", "xia", "xian", "xiang", "xiao", "xie","xin", "xing", "xiong", "xiu", "xu", "xuan", "xue", "xun", "ya","yan", "yang", "yao", "ye", "yi", "yin", "ying", "yo", "yong","you", "yu", "yuan", "yue", "yun", "za", "zai", "zan", "zang","zao", "ze", "zei", "zen", "zeng", "zha", "zhai", "zhan", "zhang","zhao", "zhe", "zhen", "zheng", "zhi", "zhong", "zhou", "zhu","zhua", "zhuai", "zhuan", "zhuang", "zhui", "zhun", "zhuo", "zi","zong", "zou", "zu", "zuan", "zui", "zun", "zuo")val instance = TransToPinYin()/*** 转换为拼音** @param str* @return*/fun transToPinYin(str: String): String {return instance.convertAll(str)}}
}

5主界面中进行adapter的适配和组件逻辑处理

package com.example.lettersnavigationimport androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.util.Log
import android.view.View
import android.widget.EditText
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.LayoutManager
import com.example.lettersnavigation.entity.Friend
import com.example.lettersnavigation.util.util.LettersSorting
import com.example.lettersnavigation.util.util.TransToPinYin
import java.util.Collections//LettersView.OnLettersListViewListener,
class MainActivity : AppCompatActivity() {private val tag=javaClass.simpleNameprivate lateinit var mLettersView:LettersViewprivate lateinit var tvToast:TextViewprivate lateinit var et_search:EditTextprivate lateinit var iv_delete:ImageViewprivate lateinit var recyclerView:RecyclerViewprivate lateinit var adapter: FriendRecyclerViewAdapterprivate lateinit var layoutManager:LayoutManagerprivate val users= listOf<String>("张三","%海","zab","abc","aac","李四", "11", "刘某人", "王五", "Android", "IOS", "王寡妇","阿三", "爸爸", "妈妈", "CoCo", "弟弟", "恩科", "知网", "下一张", "蛤蟆", "费卡拉", "哥哥", "Hi", "I", "杰克", "克星", "乐乐", "你好", "Oppo", "皮特", "曲奇饼","日啊", "思思", "%23","缇娜", "U", "V", "王大叔", "7wei","嘻嘻", "3小伙子", "撒贝宁", "吱吱", "舅舅", "老总", "隔壁老王", "许仙", "吱吱", "祝舅", "助总", "中壁老王", "赞仙", "吱吱", "做舅", "张总", "啧啧壁老王", "增仙", "在弟", "真正科", "之知网", "真一张", "总蛤蟆")override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)init()et_search.addTextChangedListener(object:TextWatcher{override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}override fun afterTextChanged(p0: Editable?) {if (p0 != null) {if(p0.isNotEmpty()){iv_delete.visibility=View.VISIBLE}else{iv_delete.visibility=View.GONE}}}})//设置监听事件mLettersView.setOnLettersListViewListener (object:LettersView.OnLettersListViewListener{override fun onLettersListener(s: String?) {val position=adapter.getPositionForName(s!![0])//这个是从下往上显现//recyclerView.scrollToPosition(position)val manager=layoutManager as LinearLayoutManager//第一个参数是跳转到指定的位置,第二个表示距离顶部的距离manager.scrollToPositionWithOffset(position,0)}})//点击删除按钮时需要将EditText中的数据删除iv_delete.setOnClickListener(){iv_delete.visibility=View.GONEet_search.text=Editable.Factory.getInstance().newEditable("")}layoutManager=LinearLayoutManager(this) as LinearLayoutManagerrecyclerView.layoutManager=layoutManager//需要对Friends链表进行按照字母排序。val friendsPinYin=parsingData()//使用工具类对字母进行排序Collections.sort(friendsPinYin,object:Comparator<Friend>{override fun compare(p0: Friend?, p1: Friend?): Int {return p0!!.firstLetter.compareTo(p1!!.firstLetter)}})adapter=FriendRecyclerViewAdapter(this,friendsPinYin)recyclerView.adapter=adapter//反向绑定,当滑动当前item时,右侧的LetterView也要进行跳转到对应的位置上recyclerView.addOnScrollListener(object :RecyclerView.OnScrollListener(){override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {super.onScrollStateChanged(recyclerView, newState)}override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {super.onScrolled(recyclerView, dx, dy)val manager=layoutManager as LinearLayoutManagerval fposition=manager.findFirstVisibleItemPosition()//val lposition=manager.findLastVisibleItemPosition()//获取到第一个显示的位置//Log.d("aafirstPosition","$fposition")// Log.d("aalastPosition","$lposition")val friendFirst=adapter.friends[fposition].firstLetter//val friendLast=adapter.friends[lposition].firstLetter//就把这个friendFirst传递给ListView//Log.d("aadiyige","$friendFirst")//Log.d("aazuihouyige","$friendLast")var indexl=0if (friendFirst!=="#"){indexl=(friendFirst[0]-'A')%26+1}//此时应该把这个值传递给LettersViewmLettersView.setCheckIndex(indexl)mLettersView.invalidate()}})}fun init(){mLettersView=findViewById(R.id.mLettersView)tvToast=findViewById(R.id.tvToast)mLettersView.setmTextView(tvToast)et_search=findViewById(R.id.et_search)iv_delete=findViewById(R.id.iv_delete)recyclerView=findViewById(R.id.myRecyclerView)}//使用工具类,将文字和英语转换成拼音,并且只保留第一个字母来进行排序比较private fun parsingData():ArrayList<Friend>{val friends=ArrayList<Friend> ()//Log.d(tag,"${users.size}")for(i in users.indices){//将名字转换成拼音val name=users[i]val pinyin=TransToPinYin.transToPinYin(name)//Log.d(tag,"${name}转化成拼音是:"+pinyin)var firstLetter=pinyin.substring(0,1).uppercase()//说明是一个大写字母if((firstLetter[0].toInt() -65) !in 0..26){firstLetter="#"}//Log.d(tag,"${name}的首字母是:"+firstLetter)val friend=Friend(firstLetter,name)friends.add(friend)}return friends}}

最后为了进入界面时不获取到Edit text的焦点,可以在清单文件中当前activity的标签之下加入

android:windowSoftInputMode="adjustUnspecified|stateHidden"

6项目完善1


完善了当首字母不是常规的26个子母时归总到#的目录之下。只需要将首字母不是字母的统一将firstletter设定为“#”即可,在主activity的数据转换函数中修改判断即可

//使用工具类,将文字和英语转换成拼音,并且只保留第一个字母来进行排序比较private fun parsingData():ArrayList<Friend>{val friends=ArrayList<Friend> ()Log.d(tag,"${users.size}")for(i in users.indices){//将名字转换成拼音val name=users[i]val pinyin=TransToPinYin.transToPinYin(name)Log.d(tag,"${name}转化成拼音是:"+pinyin)var firstLetter=pinyin.substring(0,1).uppercase()//说明不是一个大写字母if((firstLetter[0].toInt() -65) !in 0..26){firstLetter="#"}Log.d(tag,"${name}的首字母是:"+firstLetter)val friend=Friend(firstLetter,name)friends.add(friend)}return friends}

使用Kotlin+RecyclerView+自定义View实现简易的通讯录字母导航功能相关推荐

  1. 初学Kotlin——在自定义View里的应用

    什么是Kotlin Kotlin,它是JetBrains开发的基于JVM的面向对象的语言.2017年的时候被Google推荐Android的官方语言,同时Android studio 3.0正式支持这 ...

  2. Android 自定义View 仿微信好友,字母排序

    一 :具体说下思路(注意:一下代码如果没有显示则访问     https://www.jianshu.com/p/2da89b56871f   ) 1 :整体用到的控件,list view(recyc ...

  3. kotllin自定义view_GitHub - wangshuaialex/Kotlin-CustomView: Kotlin实现的自定义View(仪表盘、饼状图、圆形头像)...

    #自定义View-Kotlin版 本文的目的有两个: 大多数时候,自定义View并不会被用到,但一旦用到,通常都是很炫酷的效果.App的开发本身并不酷,让它们变酷的是设计师们的想象力与创造力.对于开发 ...

  4. 自定义view之kotlin绘制精简小米时间控件

    引言 今天玩小米mix2的时候看到了小米的时间控件效果真的很棒.有各种动画效果,3d触摸效果,然后就想着自己能不能也实现一个这样的时间控件,那就开始行动绘制一个简易版本的小米时间控件吧o((≧▽≦o) ...

  5. 【Kotlin】Kotlin 自定义组件 ( 自定义 View | 自定义 SurfaceView )

    文章目录 一.自定义 View 组件 ( Kotlin ) 二.自定义 SurfaceView 组件 ( Kotlin ) 自定义组件构造函数统一在 constructor(context: Cont ...

  6. kotlin自定义View出现 java.lang.ClassNotFoundException

    问题1:找不到所引用的自定义View Didn't find class "dxf.example.dxf.customviewdemo.MyTextView" on path: ...

  7. 嵌套RecyclerView左右滑动替代自定义view

    以前的左右滑动效果采用自定义scrollview或者linearlayout来实现,recyclerview可以很好的做这个功能,一般的需求就是要么一个独立的左右滑动效果,要么在一个列表里的中间部分一 ...

  8. kotlin实现的简单个人账户管理APP(三) 自定义View仿支付宝的密码输入框/密码相关逻辑

    转载请注明出处:http://blog.csdn.net/a512337862/article/details/78874322 前言 1.本篇博客相关的项目介绍请参考基于kotlin实现的简单个人账 ...

  9. 【Android 仿微信通讯录 导航分组列表-下】自定义View为RecyclerView打造右侧索引导航栏IndexBar

    本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 转载请标明出处: http://blog.csdn.net/zxt0601/article/details/52420706 本文出 ...

最新文章

  1. 你的登录接口真的安全吗?快看看你有没有中招!
  2. R语言ggplot2可视化分组变量下的数据分布(线条、色彩配置)、WVPlots包的ShadowHist函数比较分组下的数据直方图、ggplot2分面图facet_wrap可视化分组变量下的数据分布
  3. PHP 标准AES加密算法类
  4. linux搭建mq环境,Linux搭建servicemix、activemq环境
  5. overfitting(过度拟合)的概念
  6. mybatisplus 一次性执行多条SQL语句插入(Oracle篇)
  7. 1-1.Win10系统利用Pycharm社区版安装Django搭建一个简单Python Web项目的步骤之一
  8. 快速锁屏电脑快捷键_电脑小技巧
  9. Verilog实现3分频实例
  10. rsync下同步inotify实时同步
  11. CVE-2018-5767 栈溢出漏洞复现
  12. html+css制作小米商城官网初尝试
  13. linux 中压缩文件夹命令行,Linux 文件夹 压缩 命令
  14. Android 9.0 wifi 热点 汇总
  15. SpringBoot缓存管理
  16. 信息安全密码技术--栅栏密码
  17. SuperMap iClient 9D for MapboxGL地图风格浅析
  18. 百度地图API详解之地图标注覆盖物
  19. java基础-简单的抽奖程序
  20. 也说中国程序员的悲哀

热门文章

  1. 拼多多+携程+蚂蚁金服技术面集合,赶紧收藏!
  2. Python 获取当前是哪个季度
  3. 计算机专业有趣的事,计算机系的学生有趣的自我介绍范文3篇
  4. Smali相关的基础知识点
  5. C#:实现快速划分/快速分割算法(附完整源码)
  6. 小米开源框架mace android案例调试
  7. 数据的概率分布以及用python绘制分布图
  8. 字符串逆序的几种写法
  9. MUSIC和ESPRIT算法
  10. 十进制转换成二进制和十六进制的方法