本文主要是介绍自定义通讯录字母索引,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1、先来看下布局的效果
布局的代码如下,其中LetterIndexView为我们将要自定义的控件,使用相对布局置于界面的右侧;
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.itemp.letterindexview.MainActivity"><ListView
android:id="@+id/lvFriends"android:layout_width="match_parent"android:layout_height="match_parent"/><TextView
android:id="@+id/tvCurrentLetter"android:layout_width="100dp"android:layout_height="100dp"android:background="@drawable/shape_letterindexview_bg_pressed"android:gravity="center"android:textSize="50sp"android:layout_centerInParent="true"android:textColor="@color/white"android:textStyle="bold"android:visibility="visible"android:text="A" /><com.itemp.letterindexview.LetterIndexView
android:id="@+id/liv"android:layout_width="35dp"android:layout_height="match_parent"android:layout_margin="5dp"android:layout_alignParentRight="true"/></RelativeLayout>
2、继承于View并使用绘图法在画布上绘制字母:
public class LetterIndexView extends View
3、实现构造方法,在其中初始化画笔,并为控件设置背景图(shape资源制作的圆角矩形)
public LetterIndexView(Context context) {this(context, null);}public LetterIndexView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public LetterIndexView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);//setBackgroundResourece();setBackgroundResource(R.drawable.shape_letterindexview_bg);paint = new Paint();paint.setAntiAlias(true);//抗锯齿}
4、shape资源的定义代码:res/drawable/shape_letterindexview_bg.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"><solid android:color="#fff" /><stroke
android:width="1dp"android:color="#ddd" /><corners android:radius="10dp" />
</shape>
这是一个白色实心的圆角矩形,按下后将其变为黄色实心的圆角矩形,文件为res/drawable/shape_letterindexview_bg_pressed.xml:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"><solid android:color="#ff0" /><stroke
android:width="1dp"android:color="#ddd" /><corners android:radius="10dp" />
</shape>
5、定义字符串数组作为索引的文本:
String[] letters = 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", "#",
};
6、覆写onDraw()方法,将字母纵向排列均匀地绘制在画布上:
@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if (width == 0) {width = getWidth();height = getHeight();}//把字母画在控件上,【选中字母】用红色画笔,否则黑色for (int i = 0; i < letters.length; i++) {//计算startX,控件宽度的一半减去字母宽度的一半String letter = letters[i];float letterSize = paint.measureText(letter);float startX = (width - letterSize) / 2;//startY,上方所有单元格的高度之和+(单元格高度的一半+字母高度的一半)float unitHeight = (height - 40) / 27f;float startY = 20 + i * unitHeight + (unitHeight + letterSize) / 2;//高亮字母为红色,否则为黑色if(i == currentPosition){paint.setColor(Color.RED);}else {paint.setColor(Color.BLACK);}paint.setTextSize(35);paint.setStyle(Paint.Style.FILL_AND_STROKE);//使用加粗效果canvas.drawText(letter, startX, startY, paint);//绘制字母}}
7、接下来覆写onTouchEvent()定义手指在控件上的滑动响应,逻辑为:
·手指按下,整个控件的背景色变为黄色,并根据手指按下的y的位置,确认哪个字母为选中字母,并重绘以将该字母高亮显示,并通知外界响应按下事件(比如显示小窗口见本文末尾GIF)
·手指滑动,动态改变选中字母,并重绘以将该字母高亮显示
·手指抬起,控件背景恢复为默认的白色,并通知外界响应(比如隐藏小窗口见文章末尾GIF)
@Overridepublic boolean onTouchEvent(MotionEvent event) {float y = event.getY();switch (event.getAction()) {case MotionEvent.ACTION_DOWN://改变背景效果setBackgroundResource(R.drawable.shape_letterindexview_bg_pressed);//根据手指位置设置高亮字母并重绘invalidateCurrentPosition(y);//通知外界手指按下if (callback != null) {callback.onFingerDown(true);}break;case MotionEvent.ACTION_MOVE://根据手指位置设置高亮字母并重绘invalidateCurrentPosition(y);//通知外界字母变化if (callback != null) {callback.onLetterChanged(letters[currentPosition]);}break;case MotionEvent.ACTION_UP://恢复背景效果setBackgroundResource(R.drawable.shape_letterindexview_bg);//通知外界手指抬起if (callback != null) {callback.onFingerDown(false);}break;}return true;}/*** 根据手指位置动态设置高亮字母并重绘* @param y*/private void invalidateCurrentPosition(float y) {currentPosition = (int) ((y / height) * letters.length);if(currentPosition > 26){currentPosition = 26;}invalidate();}
11、以接口的方式通知外界:手指按下或抬起,高亮字母发生改变:
LetterIndexCallback callback;public void setCallback(LetterIndexCallback callback) {this.callback = callback;}public interface LetterIndexCallback {void onFingerDown(boolean down);void onLetterChanged(String letter);}
12、最后当外界ListView主动滚动时,字母索引的选中字母也随之变化,我们为外界提供公共方法,用于更新选中字母的位置:
/*** 供外界ListView滚动时通知到当前控件* @param firstLetter*/public void setCurrentLetter(String firstLetter) {for (int i = 0; i < letters.length; i++) {if(letters[i].equals(firstLetter)){setCurrentPosition(i);return;}}}
13、Activity实现【索引控件】的回调接口,并将自身设置给【索引控件】:
public class MainActivity extends AppCompatActivity implements LetterIndexView.LetterIndexCallback
@Overridepublic void onLetterChanged(String letter) {tvCurrentLetter.setText(letter);}@Overridepublic void onFingerDown(boolean fingerDown) {if(fingerDown){tvCurrentLetter.setVisibility(View.VISIBLE);}else {tvCurrentLetter.setVisibility(View.GONE);}}
letterIndexView.setCallback(this);
效果如下:
这篇关于自定义通讯录字母索引的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!