Android 分组ListView+索引条

  • 前言

    之前没有实现过这样的功能,最近刚好在做通讯方面的项目, 所以联系人这块需要一个分组和索引的功能, 今天我们来一起学习.

  • 分组ListView

    实现的方法有两种:

    • 每一个ItemView都有一个Header, 通过数据俩控制其显示或隐藏

    • 使用不同类型的View.

    我这里用了一个巧妙的方法.

    代码:
    1. Adapter

      可以看到这里实现了SectionIndexer接口, 这个接口用来控制ListView的分组的, 我们只要实现其中两个方法就好了, 分别是getPositionForSection(int position)和getSectionForPosition(int i).

      public class GroupListViewAdapter extends BaseAdapter implements SectionIndexer {
          private List<SortEntity> mEntities;
          private Context mContext;
      
          public GroupListViewAdapter(List<SortEntity> entities, Context context) {
              mEntities = entities;
              mContext = context;
          }
      
          @Override
          public int getCount() {
              return mEntities.size();
          }
      
          @Override
          public Object getItem(int i) {
              return mEntities.get(i);
          }
      
          @Override
          public long getItemId(int i) {
              return i;
          }
      
          @Override
          public View getView(int i, View view, ViewGroup viewGroup) {
              ViewHolder viewHolder = null;
              SortEntity sortEntity = mEntities.get(i);
              if (view == null) {
                  viewHolder = new ViewHolder();
                  view = LayoutInflater.from(mContext).inflate(R.layout.layout_item_lv, null);
                  viewHolder.mTvLetter = (TextView) view.findViewById(R.id.tv_item_letter);
                  viewHolder.mTvTitle = (TextView) view.findViewById(R.id.tv_item_title);
                  view.setTag(viewHolder);
              } else {
                  viewHolder = (ViewHolder) view.getTag();
              }
              //下面就是来给字母分组
              int section = getSectionForPosition(i);
              if (i == getPositionForSection(section)) {
                  viewHolder.mTvLetter.setVisibility(View.VISIBLE);
                  viewHolder.mTvLetter.setText(sortEntity.getSortLetters());
              } else {
                  viewHolder.mTvLetter.setVisibility(View.GONE);
              }
              viewHolder.mTvTitle.setText(sortEntity.getName());
              return view;
          }
      
          class ViewHolder {
              TextView mTvTitle;
              TextView mTvLetter;
          }
      
          @Override
          public Object[] getSections() {
              return null;
          }
      
          //通过首字母的ascii码来获取在Listview中第一次出现该首字母的位置
          @Override
          public int getPositionForSection(int position) {
              for (int i = 0; i < getCount(); i++) {
                  String sortStr = mEntities.get(i).getSortLetters();
                  char firstChar = sortStr.toUpperCase().charAt(0);
                  if (firstChar == position) {
                      return i;
                  }
              }
              return -1;
          }
      
          //根据ListView的position来获取该位置的首字母的ASCII码值
          @Override
          public int getSectionForPosition(int i) {
              return mEntities.get(i).getSortLetters().charAt(0);
          }
      }
    2. SortEntity

      算是一个实体类, 实现了一个排序接口

      public class SortEntity implements Comparator<SortEntity> {
          private String mName;
          private String mSortLetters;
      
          public String getName() {
              return mName;
          }
      
          public void setName(String name) {
              mName = name;
          }
      
          public String getSortLetters() {
              return mSortLetters;
          }
      
          public void setSortLetters(String sortLetters) {
              mSortLetters = sortLetters;
          }
      
          @Override
          public int compare(SortEntity t1, SortEntity t2) {
              return t1.getSortLetters().compareTo(t2.getSortLetters());
          }
      }
    • 通过上面的ListView我们很方便的就可以实现这个索引栏

      自定义的View, 实现如下:

      public class SideBar extends View {
          //分类字母
          private static String[] sSideBarTitle;
          private int mChoose = -1;   //选择标记
          private Paint mPaint;       //画笔
          private TextView mTvDialog; //显示框
          private OnTouchLetterChangeListener mListener;  //回调接口
          int mHeight = 0;
          int mWidth = 0;
          int mSingleTextHeight;
      
          public SideBar(Context context) {
              super(context);
              initView();
          }
      
          public SideBar(Context context, @Nullable AttributeSet attrs) {
              super(context, attrs);
              initView();
          }
      
          public SideBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
              super(context, attrs, defStyleAttr);
              initView();
          }
      
          private void initView() {
              sSideBarTitle = getResources().getStringArray(R.array.sidebar);
              mPaint = new Paint();
              setPaint();
          }
      
          private void setPaint() {
              mPaint.reset();
              mPaint.setColor(Color.WHITE);
              mPaint.setAntiAlias(true);
              mPaint.setTypeface(Typeface.DEFAULT_BOLD);
              mPaint.setTextSize(30);
          }
      
      
          @Override
          protected void onSizeChanged(int w, int h, int oldw, int oldh) {
              super.onSizeChanged(w, h, oldw, oldh);
              mHeight = getMeasuredHeight();
              mWidth = getMeasuredWidth();
              mSingleTextHeight = mHeight / sSideBarTitle.length;
          }
      
          @Override
          protected void onDraw(Canvas canvas) {
              super.onDraw(canvas);
              for (int i = 0; i < sSideBarTitle.length; i++) {
                  if (i == mChoose) {
                      mPaint.setColor(getResources().getColor(R.color.colorAccent));
                      mPaint.setFakeBoldText(true);
                  }
                  float xPos = mWidth / 2 - mPaint.measureText(sSideBarTitle[i]) / 2;
                  float yPos = mSingleTextHeight * i + mSingleTextHeight;
                  canvas.drawText(sSideBarTitle[i], xPos, yPos, mPaint);
                  setPaint();
              }
          }
      
          @Override
          public boolean dispatchTouchEvent(MotionEvent event) {
              int action = event.getAction();
              float y = event.getY();
              int lastChoose = mChoose;
              int scale = (int) (y / getHeight() * sSideBarTitle.length);
              switch (action) {
                  case MotionEvent.ACTION_UP:
                      mChoose = -1;
                      if (mTvDialog != null) {
                          mTvDialog.setVisibility(View.INVISIBLE);
                      }
                      break;
                  default:
                      if (lastChoose != scale) {
                          if (scale >= 0 && scale < sSideBarTitle.length) {
                              if (mListener != null) {
                                  mListener.letterChange(sSideBarTitle[scale]);
                              }
                              if (mTvDialog != null) {
                                  mTvDialog.setText(sSideBarTitle[scale]);
                                  mTvDialog.setVisibility(View.VISIBLE);
                              }
                              mChoose = scale;
                          }
                      }
                      break;
              }
              invalidate();
              return true;
          }
      
      
          public void setOnTouchLetterChangeListener(OnTouchLetterChangeListener onTouchLetterChangeListener) {
              this.mListener = onTouchLetterChangeListener;
          }
      
          public interface OnTouchLetterChangeListener {
              void letterChange(String s);
          }
      
          public void setTvDialog(TextView tvDialog) {
              mTvDialog = tvDialog;
          }
      }

    • MainActivity

      主要就是数据的处理, 和接口的回调

      public class MainActivity extends AppCompatActivity {
      
          private ListView mLvFriends;
          private Toolbar mTb;
          private List<SortEntity> mFriends;
          private Handler mHandler;
          private String mUserId;
          private GroupListViewAdapter mAdapter;
          private SortEntity mSortEntity;
          private SideBar mSideBar;
          private TextView mTvDialog;
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
              initView();
              initEvent();
          }
      
          private void initView(){
              mLvFriends = (ListView) findViewById(R.id.lv_main);
              mSideBar = (SideBar) findViewById(R.id.sidebar);
              mTvDialog = (TextView) findViewById(R.id.tv_dialog);
              mSideBar.setTvDialog(mTvDialog);
              mSortEntity = new SortEntity();
      
          }
      
          private void initEvent(){
              mFriends = fillData(getResources().getStringArray(R.array.title));
              Collections.sort(mFriends, mSortEntity);    //对list排序
              mAdapter = new GroupListViewAdapter(mFriends, this);
              //接口的回调
              mSideBar.setOnTouchLetterChangeListener(new SideBar.OnTouchLetterChangeListener() {
                  @Override
                  public void letterChange(String s) {
                      int position = mAdapter.getPositionForSection(s.charAt(0));
                      if (position != -1) {
                          mLvFriends.setSelection(position);
                      }
                  }
              });
              mLvFriends.setAdapter(mAdapter);
          }
      
          //填充数据
          private List<SortEntity> fillData(String[] data) {
              List<SortEntity> entities = new ArrayList<>();
              for (int i = 0; i < data.length; i++) {
                  SortEntity sortEntity = new SortEntity();
                  sortEntity.setName(data[i]);
                  sortEntity.setSortLetters(data[i].substring(0, 1).toUpperCase());
                  entities.add(sortEntity);
              }
              return entities;
          }
      }

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值