美文网首页Android开发Android知识程序员
一个仿手机联系人自动排序的列表实现sortlistview(一

一个仿手机联系人自动排序的列表实现sortlistview(一

作者: 不识水的鱼 | 来源:发表于2017-12-19 15:46 被阅读100次

    一个仿手机联系人自动排序的列表实现sortlistview(一)

    先上图,直接看预览,只是右边的一个导航条

    我的github链接

    来自网络的图片

    三种效果的截图,

    S71219-14192930.jpg
    S71219-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);
        }
    }
    

    在下一篇就能完成基本的功能,要使用到这里的这个silderbar

    一个仿手机联系人自动排序的列表实现sortlistview(二)
    参考链接

    相关文章

      网友评论

        本文标题: 一个仿手机联系人自动排序的列表实现sortlistview(一

        本文链接:https://www.haomeiwen.com/subject/gmxiwxtx.html