Android自訂View實現字母導覽列_Android

來源:互聯網
上載者:User

很多的Android入門程式猿來說對於Android自訂View,可能都是比較恐懼的,但是這又是高手進階的必經之路,所有準備在自訂View上面花一些功夫,多寫一些文章。

思路分析:

1、自訂View實現字母導覽列

2、ListView實現連絡人清單

3、字母導覽列滑動事件處理

4、字母導覽列與中間字母的聯動

5、字母導覽列與ListView的聯動

效果圖:

首先,我們先甩出主布局檔案,方便後面代碼的說明

<!--?xml version="1.0" encoding="utf-8"?--><linearlayout android:layout_height="match_parent" android:layout_width="match_parent" android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android">  <edittext android:background="@drawable/search_border" android:drawableleft="@android:drawable/ic_menu_search" android:layout_height="wrap_content" android:layout_width="match_parent" android:padding="8dp">  <relativelayout android:layout_height="match_parent" android:layout_width="match_parent">  <listview android:divider="@null" android:id="@+id/lv" android:layout_height="match_parent" android:layout_width="match_parent">  <textview android:background="#888888" android:gravity="center" android:id="@+id/tv" android:layout_centerinparent="true" android:layout_height="50dp" android:layout_width="50dp" android:textcolor="#000000" android:textsize="18dp" android:visibility="gone">  <com.handsome.tulin.view.navview android:id="@+id/nv" android:layout_alignparentright="true" android:layout_height="match_parent" android:layout_margin="16dp" android:layout_width="20dp"> </com.handsome.tulin.view.navview></textview></listview></relativelayout></edittext></linearlayout>

步驟一:分析自訂字母導覽列

思路分析:

1、我們在使用的時候把寬設定為20dp,高設定為填充父控制項,所以這裡擷取的寬度為20dp

2、通過迴圈,畫出豎直的字母,每畫一次得重新設定一下顏色,因為我們需要一個選中的字母顏色和預設不一樣

public class NavView extends View { private Paint textPaint = new Paint(); private String[] s = 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", "#"}; //滑鼠點擊、滑動時選擇的字母 private int choose = -1; //中間的文本 private TextView tv; public NavView(Context context, AttributeSet attrs) {  super(context, attrs); } public NavView(Context context) {  super(context); }  public NavView(Context context, AttributeSet attrs, int defStyleAttr) {  super(context, attrs, defStyleAttr); }  private void initPaint() {  textPaint.setTextSize(20);  textPaint.setAntiAlias(true);  textPaint.setColor(Color.BLACK); }  @Override protected void onDraw(Canvas canvas) {  super.onDraw(canvas);  //畫字母  drawText(canvas); } /**  * 畫字母  *  * @param canvas  */ private void drawText(Canvas canvas) {  //擷取View的寬高  int width = getWidth();  int height = getHeight();  //擷取每個字母的高度  int singleHeight = height / s.length;  //畫字母  for (int i = 0; i < s.length; i++) {   //畫筆預設顏色   initPaint();   //高亮字母顏色   if (choose == i) {    textPaint.setColor(Color.RED);   }   //計算每個字母的座標   float x = (width - textPaint.measureText(s[i])) / 2;   float y = (i + 1) * singleHeight;   canvas.drawText(s[i], x, y, textPaint);   //重設顏色   textPaint.reset();  } }}

步驟二:ListView實現連絡人清單

思路分析:

1、在主Activity中,定義一個資料數組,使用工具類擷取數組的第一個字母,使用Collections根據第一個字母進行排序,由於工具類有點長,就不貼出來了。

2、建立一個ListView子布局,建立一個Adapter進行填充。

主布局:

public class MainActivity extends AppCompatActivity { private TextView tv; private ListView lv; private NavView nv; private List<user> list; private UserAdapter adapter; private String[] name = new String[]{   "潘粵明", "戴軍", "薛之謙", "藍雨", "任泉", "張傑", "秦俊傑",   "陳坤", "田亮", "夏雨", "保劍鋒", "陸毅", "喬振宇", "吉傑", "郭敬明", "巫迪文", "歡子", "井柏然",   "左小祖咒", "段奕宏", "毛寧", "樊凡", "湯潮", "山野", "陳龍", "侯勇", "俞思遠", "馮紹峰", "崔健",   "杜淳", "張翰", "彭坦", "柏栩栩", "蒲巴甲", "淩瀟肅", "毛方圓", "武藝", "耿樂", "錢泳辰"}; @Override protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.activity_main);  initView();  initData(); } private void initView() {  tv = (TextView) findViewById(R.id.tv);  lv = (ListView) findViewById(R.id.lv);  nv = (NavView) findViewById(R.id.nv);  nv.setTextView(tv); } private void initData() {  //初始化資料  list = new ArrayList<>();  for (int i = 0; i < name.length; i++) {   list.add(new User(name[i], CharacterUtils.getFirstSpell(name[i]).toUpperCase()));  }  //將拼音排序  Collections.sort(list, new Comparator<user>() {   @Override   public int compare(User lhs, User rhs) {    return lhs.getFirstCharacter().compareTo(rhs.getFirstCharacter());   }  });  //填充ListView  adapter = new UserAdapter(this, list);  lv.setAdapter(adapter); }}</user></user>

ListView子布局:

<!--?xml version="1.0" encoding="utf-8"?--><linearlayout android:background="#ffffff" android:layout_height="match_parent" android:layout_width="match_parent" android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android">  <textview android:background="#DBDBDA" android:id="@+id/tv_firstCharacter" android:layout_height="wrap_content" android:layout_width="match_parent" android:padding="8dp" android:text="A" android:textcolor="#000000" android:textsize="14dp">  <textview android:background="#ffffff" android:id="@+id/tv_name" android:layout_height="wrap_content" android:layout_width="match_parent" android:padding="8dp" android:text="張棟樑" android:textcolor="#2196F3" android:textsize="14dp"> </textview></textview></linearlayout>

Adapter:

public class UserAdapter extends BaseAdapter { private List<user> list; private User user; private LayoutInflater mInflater; private Context context; public UserAdapter(Context context, List<user> list) {  this.list = list;  mInflater = LayoutInflater.from(context);  this.context = context; } @Override public int getCount() {  return list.size(); } @Override public Object getItem(int position) {  return list.get(position); } @Override public long getItemId(int position) {  return position; } @Override public View getView(int position, View convertView, ViewGroup parent) {  if (convertView == null) {   convertView = mInflater.inflate(R.layout.adapter_user, null);  }  ViewHolder holder = getViewHolder(convertView);  user = list.get(position);  if (position == 0) {   //第一個資料要顯示字母和姓名   holder.tv_firstCharacter.setVisibility(View.VISIBLE);   holder.tv_firstCharacter.setText(user.getFirstCharacter());   holder.tv_name.setText(user.getUsername());  } else {   //其他資料判斷是否為同個字母,這裡使用Ascii碼比較大小   if (CharacterUtils.getCnAscii(list.get(position - 1).getFirstCharacter().charAt(0)) <     CharacterUtils.getCnAscii(user.getFirstCharacter().charAt(0))) {    //後面字母的值大於前面字母的值,需要顯示字母    holder.tv_firstCharacter.setVisibility(View.VISIBLE);    holder.tv_firstCharacter.setText(user.getFirstCharacter());    holder.tv_name.setText(user.getUsername());   } else {    //後面字母的值等於前面字母的值,不顯示字母    holder.tv_firstCharacter.setVisibility(View.GONE);    holder.tv_name.setText(user.getUsername());   }  }  return convertView; } /**  * 獲得控制項管理對象  *  * @param view  * @return  */ private ViewHolder getViewHolder(View view) {  ViewHolder holder = (ViewHolder) view.getTag();  if (holder == null) {   holder = new ViewHolder(view);   view.setTag(holder);  }  return holder; } /**  * 控制項管理類  */ private class ViewHolder {   private TextView tv_firstCharacter, tv_name;   ViewHolder(View view) {   tv_firstCharacter = (TextView) view.findViewById(R.id.tv_firstCharacter);   tv_name = (TextView) view.findViewById(R.id.tv_name);  } }  /**  * 通過字元尋找位置  *  * @param s  * @return  */ public int getSelectPosition(String s) {  for (int i = 0; i < getCount(); i++) {   String firChar = list.get(i).getFirstCharacter();   if (firChar.equals(s)) {    return i;   }  }  return -1; }}</user></user>

步驟三:字母導覽列滑動事件處理、字母導覽列與中間字母的聯動

思路分析:

1、在自訂View中重寫dispatchTouchEvent處理滑動事件,最後返回true。

2、在主Activity傳進來一個TextView,在我們滑動的時候設定Text,鬆開的時候消失Text。設定Text的時候需要計算Text的位置,並且滑過多的話會出現數組越界的問題,所以我們在裡面處理數組越界問題。

3、最後,提供一個介面,記錄我們滑到的字母,為了後面可以和ListView聯動。

@Overridepublic boolean dispatchTouchEvent(MotionEvent event) { //計算選中字母 int index = (int) (event.getY() / getHeight() * s.length); //防止腳標越界 if (index >= s.length) {  index = s.length - 1; } else if (index < 0) {  index = 0; } switch (event.getAction()) {  case MotionEvent.ACTION_DOWN:  case MotionEvent.ACTION_MOVE:   setBackgroundColor(Color.GRAY);   //選中字母高亮   choose = index;   //出現中間文字   tv.setVisibility(VISIBLE);   tv.setText(s[choose]);   //調用ListView連動介面   if (listener != null) {    listener.touchCharacterListener(s[choose]);   }   //重繪   invalidate();   break;  default:   setBackgroundColor(Color.TRANSPARENT);   //取消選中字母高亮   choose = -1;   //隱藏中間文字   tv.setVisibility(GONE);   //重繪   invalidate();   break; } return true;}public onTouchCharacterListener listener;public interface onTouchCharacterListener { void touchCharacterListener(String s);} public void setListener(onTouchCharacterListener listener) { this.listener = listener;} /** * 傳進來一個TextView * * @param tv */public void setTextView(TextView tv) { this.tv = tv;}

步驟四:字母導覽列和ListView的聯動

思路分析:

1、我們已經通過介面傳遞過去了一個選擇的字母,和在adapter寫好了根據字母查詢position的方法,這個時候只要主Activity對自訂View設定監聽,判斷即可。

//ListView連動介面nv.setListener(new NavView.onTouchCharacterListener() { @Override public void touchCharacterListener(String s) {  int position = adapter.getSelectPosition(s);  if (position != -1) {   lv.setSelection(position);  } }});

以上就是本文的全部內容,希望對大家的學習有所協助,也希望大家多多支援雲棲社區。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.