一个仿手机联系人自动排序的列表实现sortlistview
(一)
先上图,直接看预览,只是右边的一个导航条
来自网络的图片三种效果的截图,
S71219-14192930.jpgS71219-14193705.jpg
S71219-14191837.jpg
在项目中,这种列表很常见,类似于手机联系人,或者聊天的人员列表,可以快速的定位到我们需要找到的信息
这里是第一篇,实现右边的导航,一步一步实现。
实现的原理如下:
自定义view,继承与Textview,基本设置没什么特别的,看代码:
private 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", "#"};
这里是需要的符号实现列表字母排序。
在手势的触摸事件里,获取到我们需要的y
坐标
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
//保证在文字上才获取y
if(event.getX()>(w-getPaddingRight()-singleTextH-10)) {
eventY = event.getY();
invalidate();
return true;
}else{
eventY = 0;
invalidate();
break;
}
case MotionEvent.ACTION_CANCEL:
//只有normal才会回调
if(style==2){
//离开的回调
callBack.onSelectEnd();
}
eventY = 0;
invalidate();
return true;
case MotionEvent.ACTION_UP:
//只有normal才会回调
if(style==2){
//离开的回调
callBack.onSelectEnd();
}
//滑动离开文字
if(event.getX()>(w-getPaddingRight()-singleTextH-10)) {
eventY = 0;
invalidate();
return true;
}else
break;
}
return super.onTouchEvent(event);
}
获取到了y
坐标,为了后续的坐标位置作安排
@Override
protected void onDraw(Canvas canvas) {
this.canvas = canvas;
DrawView(eventY);
}
下面才是正式的逻辑
//更具y来实现绘制,即点击在文字上
private void DrawView(float y) {
int currentSelectIndex = -1;
//有触摸才绘制大文字
if (y != 0) {
for (int i = 0; i < letters.length; i++) {
//当前的高度
float currentItemY = itemH * i;
//下一个的高度
float nextItemY = itemH * (i + 1);
//判断位置在点中的字母间
if (y >= currentItemY && y < nextItemY) {
currentSelectIndex = i;
if(callBack!=null){
callBack.onSelectStr(currentSelectIndex,letters[i]);
}
//画大的字母
Paint.FontMetrics fontMetrics = bigTextPaint.getFontMetrics();
//文字绘制,有基线的区别,获取到文字的高度
float bigTextSize = fontMetrics.descent - fontMetrics.ascent;
//判断类型
if(style==0||style==1){
//绘制字母,大文字
canvas.drawText(letters[i], w - getPaddingRight() - scaleWidth - bigTextSize, singleTextH + itemH * i, bigTextPaint);
}
//2才会回调
if(style==2){
//选中的回调
callBack.onSelectStart();
}
}
}
}
//其他的绘制
drawLetters(y, currentSelectIndex);
}
在代码里面写了很多注释了,可以直接看看
这样最后才是最后的绘制,如下:
private void drawLetters(float y, int index) {
//第一次进来没有缩放情况,默认画原图
if (index == -1) {
w = getMeasuredWidth();
h = getMeasuredHeight();
//每一个字母的高度
itemH = h / letters.length;
Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
//文字绘制,有基线的区别,获取到文字的高度
singleTextH = fontMetrics.descent - fontMetrics.ascent;
//绘制字母,每个item
for (int i = 0; i < letters.length; i++) {
canvas.drawText(letters[i], w - getPaddingRight(), singleTextH + itemH * i, textPaint);
}
//触摸的时候画缩放图
} else {
//遍历所有字母
for (int i = 0; i < letters.length; i++) {
//要画的字母的起始Y坐标
float currentItemToDrawY = singleTextH + itemH * i;
float centerItemToDrawY;
if (index < i)
centerItemToDrawY = singleTextH + itemH * (index + scaleItemCount);
else
centerItemToDrawY = singleTextH + itemH * (index - scaleItemCount);
//最麻烦的计算,距离当前点中的字母的距离远,则比例越小,距离x越小 (delta在字母移动范围内为0-1)
float delta = 1 - Math.abs((y - currentItemToDrawY) / (centerItemToDrawY - currentItemToDrawY));
// Log.i("size", letters[i] + "--->" + delta + "");
float maxRightX = w - getPaddingRight();
//如果大于0,表明在y坐标上方
scaleTextPaint.setTextSize(getTextSize() + getTextSize() * delta);
// Log.i("scaleTextPaint_size",getTextSize() + getTextSize() * delta+"");
float drawX = maxRightX - scaleWidth * delta;
//超出边界直接花在边界上
if (style==0){//波浪形状
if (drawX > maxRightX) {
//画边上的字母
canvas.drawText(letters[i], maxRightX, singleTextH + itemH * i, textPaint);
}else {
//画弧线字母
canvas.drawText(letters[i], drawX, singleTextH + itemH * i, scaleTextPaint);
}
//没有波浪
}else {
canvas.drawText(letters[i], maxRightX, singleTextH + itemH * i, textPaint);
}
}
这样才算是绘制完成,如上图的效果
其中有几个开放的方法,可以设置一些属性
如下:
/**
* 设置字体缩放比例
* @param scale
*/
public void setScaleTime(int scale){
scaleTime=scale;
invalidate();
}
/**
* 设置缩放字体的个数,即开口大小
* @param scaleItemCount
*/
public void setScaleItemCount(int scaleItemCount){
this.scaleItemCount=scaleItemCount;
invalidate();
}
/**
* 设置样式
* @param style
*/
public void setStyle(int style){
this.style=style;
}
下面是使用
<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"
xmlns:sidebar="http://schemas.android.com/apk/res-auto"
tools:context="com.yukunkun.SilderBarActivity">
<LinearLayout android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button android:layout_width="wrap_content"
android:onClick="wave"
android:text="wave"
android:layout_height="wrap_content"/>
<Button android:layout_width="wrap_content"
android:text="nowave"
android:onClick="nowave"
android:layout_height="wrap_content"/>
<Button android:layout_width="wrap_content"
android:text="normal"
android:onClick="normal"
android:layout_height="wrap_content"/>
</LinearLayout>
<com.yukunkun.SideBar
android:textColor="@color/colorAccent"
android:textSize="15sp"
android:paddingRight="10dp"
sidebar:scaleTime="1"
android:layout_width="200dp"
android:id="@+id/bar"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"/>
<TextView android:layout_width="55dp"
android:text="A"
android:id="@+id/tv"
android:gravity="center"
android:textSize="25sp"
android:visibility="gone"
android:textColor="#bb4e79f1"
android:background="@color/green"
android:layout_centerInParent="true"
android:layout_height="55dp"/>
</RelativeLayout>
在Activity
里:
public class SilderBarActivity extends AppCompatActivity {
private SideBar mSideBar;
private TextView mTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_silder_bar);
mSideBar = (SideBar) findViewById(R.id.bar);
mTextView = (TextView) findViewById(R.id.tv);
mSideBar.setOnStrSelectCallBack(new ISideBarSelectCallBack() {
@Override
public void onSelectStr(int index, String selectStr) {
mTextView.setText(selectStr);
}
@Override
public void onSelectEnd() {
//只有SideBar.STYLENORMAL才会调用这个方法
mTextView.setVisibility(View.GONE);
}
@Override
public void onSelectStart() {
//只有SideBar.STYLENORMAL才会调用这个方法
mTextView.setVisibility(View.VISIBLE);
}
});
}
//设置三种style
public void wave(View view) {
mSideBar.setStyle(SideBar.STYLEWAVE);
}
public void nowave(View view) {
mSideBar.setStyle(SideBar.STYLENOWAVE);
}
public void normal(View view) {
mSideBar.setStyle(SideBar.STYLENORMAL);
}
}
网友评论