Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 淺談android中手機聯系人字母索引表的實現

淺談android中手機聯系人字母索引表的實現

編輯:關於Android編程

實際上字母索引表的效果,可以說在現在的眾多APP中使用的非常流行,比如支付寶,微信中的聯系人,還有購物,買票的APP中選擇全國城市,切換城市的時候,這時候的城市也就是按照一個字母索引的順序來顯示,看起來是很方便的.其實這種字母索引表的效果最開始是出現在微信的聯系人中.因為覺得這種效果功能在今後的項目中可以說是非常常見,可能會用的上,所以准備來波博客講述一下實現的原理,一來方便以後自己復習,二來如果能夠幫助一些android路上奮斗小伙伴也是蠻有意義的.
下面我們先來看下效果圖,


看完效果圖後我們可以來分析一下這個看似很復雜的功能怎麼分解成一個個小功能來實現.要想實現如下的demo效果,主要關注在四個大的方面:
1,實現右側浮動字母索引項的列表:
問題分析:
右側浮在表面的字母豎向排列的view的實現,並且點擊view中相應的字母,會彈出一個自定義的對話框,並且對話框只有一個TextView用於顯示過那個點擊後的字母,並且仔細觀察這個彈出的字母對話框還會延遲一段時間才會消失,還有一個很重要也是很明顯的效果:就是點擊相應右邊的豎向字母列表中的字母的時候並與中間的顯示聯系人的ListView中的字母item中的字母相等的時候,才會彈出字母對話框並且會將聯系人列表中的對應的字母item頂到界面的頂部顯示,最後還有一點就是這個豎向的view實際上在上下滑動的時候會不斷改變彈出的內容以及聯系人列表中的字母項不斷跳動.
實現方法:
通過自定義一個view,來准確繪制出字母項索引,因為還需要實現當我們點擊浮動字母列表時,彈出被點擊的字母text,所以很容易就想到
在這個自定義的右側浮動字母索引項的列表中應該還有一個我們自定義的監聽器,監聽字母索引表的點擊和滑動事件,利用監聽器中的回調方法中的參數返回我們的點擊或者滑動到字母,如果我們點擊或者滑動的字母正好與我們聯系人列表中的字母索引相等,才會去彈出字母顯示框


2,實現聯系人list列表效果:
問題分析:
第二點就是聯系人那種已經按照字母表排好序的列表ListView的實現,這種ListView是怎麼實現的呢?實現這種相同首字母的聯系人放在一起顯示,並在這些相同首字母的聯系人子列表的最前面加上一個字母索引項.
解決辦法:這個我是在我以前自己封裝的CommonAdapter進行擴展的,很是方便,至於CommonAdapter(即打造ListView的通用適配器封裝)的封裝個人靈感和取經於android大神hyman,不過自己CommAdapter有點自己見解,最近一直在整理,希望出一期有關listView和GridView的博客

3,獲取聯系人數據: 聯系人數據從哪來?因為是讀取手機中的聯系人,所以很簡單用我們非常熟悉的android中的四大組件之一ContentProvider
來獲得手機中自帶應用中的數據庫.很開心的就是拿數據的時候我們可以看到在raw_contact表中的phonebook_label字段中保存了聯系人中文第一個字的首字母.所以我們就省去了取得每一個聯系人的中文第一個字拼音的首字母,並且還得借助pinyin4.jar獲得每個中文漢字的拼音,從而可以拿到首字拼音的首字母,然後將這些字母以及相應聯系人的信息作為一個Bean類保存起來,最後可以使用一個Bean類的集合對象來存儲手機聯系人的信息.即使我們拿到相應的首字拼音的首字母 放入到相應的集合中去,此時的集合時不合格的,我們需要將集合的數據對象,按照其對應的首字拼音的首字母排序,從a-z
排序主要用到了Collections.sort(list,compator)以及定義一個Compator比較對象.這樣最後就取得拿到的數據並且按照聯系人首字的拼音的首字母從a到z的排序好的集合.


4,整合建立關系:
做到這裡就是各個方面的工作都完成了,但是三件事貌似沒什麼關系,但是有一種關系千萬別忽略了就是點擊了豎向字母表中的字母的時候此時聯系人列表中的字母索引項會跟著點擊的字母變化而跳到頂部位置.所以需要建立關聯就是通過一個viewpager.setSelection()方法就行了


以上就是整個自定義view實現手機聯系人的字母索引表的實現大致思路邏輯.


那麼我們就開始吧

第一,首先我們來解決自定義View實現浮動的字母索引項的列表.

 

package com.mikyou.contactdemo.myview;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class MikyouLetterListView extends View {

	private OnTouchingLetterChangedListener listener;
	//定義了顯示在最右邊的浮動的索引項的列表,當然這個是固定的,所以可以直接初始化,如果需要變動的話則可以通過自定義屬性來指定
	String[] b = {  "#","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"};
	int choose = -1;//用於標記點擊存放字母數組中的下標
	Paint paint = new Paint();
	boolean showBkg = false;//這個boolean變量主要是控制當我們點擊索引列表中整個索引列表的背景有個變化,為false表示開始沒點擊背景為正常顯示時候的背景

	public MikyouLetterListView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	public MikyouLetterListView(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public MikyouLetterListView(Context context) {
		super(context);
	}


	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		if (showBkg) {//如果此時為true的話則表示需要改變整個canvas背景也即是索引項的背景
			canvas.drawColor(Color.parseColor("#10000000"));
		}
		/**
		 * 注意:在自定義view中的如果不需要設置wrap_content屬性就不需要自己重寫onMeasure方法
		 * 因為在onMeasure方法中系統默認會自動測量兩種模式:一個是match_parent另一個則是自己指定明確尺寸大小
		 * 這兩種方法對應著這一種MeasureSpec.AT_MOST測量模式,由於我們設置這個自定義浮動的字母索引表寬度是指定明確大小
		 * 高度是match_parent模式,所以這裡就不要手動測量了直接通過getHeight和getWidth直接拿到系統自動測量好高度和寬度
		 * */
		int height = getHeight();
		int width = getWidth();
		//讓整個顯示的每個字母均分整個屏幕高度尺寸,這個singleHeight就是每個字母占據的高度
		int singleHeight = height / b.length;
		//遍歷循環繪制每一個字母text
		for (int i = 0; i < b.length; i++) {

			//繪制字母text的顏色
			paint.setColor(Color.parseColor("#515151"));
			//繪制字母text的字體大小
			paint.setTextSize(25);
			//繪制字母text的字體樣式
			paint.setTypeface(Typeface.DEFAULT_BOLD);
			//設置抗鋸齒樣式
			paint.setAntiAlias(true);
			if (i == choose) {//判斷如果點擊字母的下標等於i,那麼就會設置繪制點擊字母的樣式用於高亮顯示
				paint.setColor(Color.parseColor("#3399ff"));
				paint.setFakeBoldText(true);
			}
			/**
			 * 注意:canvas在繪制text的時候,他繪制的起點不是text的左上角而是它的左下角
			 * (xPos,yPos)表示每個字母左下角的位置的坐標
			 *xPos = width / 2 - paint.measureText(b[i]) / 2:意思很容易理解,就是用
			 * (總的view的寬度(可能還包括leftPadding和rightPadding的大小)-每個字母寬度)/2得到就是每個字母的左下角的X坐標,
			 * 仔細想下每個text的起點的x坐標都是一樣的.paint.measureText(b[i])得到每一個字母寬度大小
			 * 由於是左下角,所以它們的Y坐標:應該如下設置 yPos = singleHeight * i + singleHeight;
			 * */
			float xPos = width / 2 - paint.measureText(b[i]) / 2;//得到繪制字母text的起點的X坐標
			float yPos = singleHeight * i + singleHeight;//得到繪制字母text的起點的Y坐標
			canvas.drawText(b[i], xPos, yPos, paint);//開始繪制每個字母
			paint.reset();//繪制完一個字母需要重置一下畫筆對象
		}

	}

	@Override
	public boolean dispatchTouchEvent(MotionEvent event) {//重寫view的觸摸事件分發方法
		final int action = event.getAction();
		final float y = event.getY();//由於只涉及到Y軸坐標,只獲取y坐標
		final int oldChoose = choose;//oldChoose用於記錄上一次點擊字母所在字母數組中的下標
		final int c = (int) (y / getHeight() * b.length);//得到點擊或觸摸的位置從而確定對應點擊或觸摸的字母所在字母數組中的下標
		switch (action) {
			case MotionEvent.ACTION_DOWN://監聽按下事件
				showBkg = true;//按下後整個view的背景變色,showBkg為true
				if (oldChoose != c && listener != null) {//如果此次點擊的字母數組下標不等於上一次的且已經注冊了監聽事件的,
					if (c >= 0 && c <= b.length) {//並且點擊得到數組下標在字母數組范圍內的,我們就將此時的字母回調出去
						listener.onTouchingLetterChanged(b[c]);//我們就將此時的對應在字母數組中的字母回調出去
						choose = c;//並且更新當前選中的字母下標存儲在choose變量中
						invalidate();//最後通知canvas重新繪制
					}
				}

				break;
			case MotionEvent.ACTION_MOVE://監聽移動事件,因為按下的時候已經把背景showBkg設置true,這裡就不需要重新設置,其他操作與按下的事件一致
				if (oldChoose != c && listener != null) {
					if (c >= 0 && c <= b.length) {
						listener.onTouchingLetterChanged(b[c]);
						choose = c;
						invalidate();
					}
				}
				break;
			case MotionEvent.ACTION_UP://監聽手指抬起的動作
				showBkg = false;//此時的背景將會恢復到初始狀態,showBkg=false
				choose = -1;//此時記錄下標的變量也需要重置
				invalidate();//並且重繪整個view
				break;
		}
		return true;
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		return super.onTouchEvent(event);
	}
	/**
	 * 注冊自定義監聽器
	 * */
	public void setOnTouchingLetterChangedListener(
			OnTouchingLetterChangedListener listener) {
		this.listener = listener;
	}
	/**
	 * 定義一個接口,用於回調出點擊後的字母,顯示在彈出的字母對話框中
	 * */
	public interface OnTouchingLetterChangedListener {
		public void onTouchingLetterChanged(String s);
	}

}
第二,點擊字母後彈出的字母框的布局和樣式的實現(這個比較簡單彈出框就是一個TextView控件):

 

 

overlay.xml(布局)


overlay_bg.xml(布局樣式):



    

    

    


第三,保存聯系人對象的Bean類:

 

 

package com.mikyou.myguardian.bean;

import java.io.Serializable;

/**
 * Created by mikyou on 16-7-19.
 */
public class ContactBean implements Serializable {
    private int iconId;
    private String title;
    private String phoneNum;
    private String firstHeadLetter;

    public ContactBean(int iconId, String title, String phoneNum, String firstHeadLetter) {
        this.iconId = iconId;
        this.title = title;
        this.phoneNum = phoneNum;
        this.firstHeadLetter=firstHeadLetter;
    }

    public ContactBean() {

    }

    public int getIconId() {
        return iconId;
    }

    public String getFirstHeadLetter() {
        return firstHeadLetter;
    }

    public void setFirstHeadLetter(String firstHeadLetter) {
        this.firstHeadLetter = firstHeadLetter;
    }
    public void setIconId(int iconId) {
        this.iconId = iconId;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getPhoneNum() {
        return phoneNum;
    }

    public void setPhoneNum(String phoneNum) {
        this.phoneNum = phoneNum;
    }

    
    @Override
    public String toString() {
        return "ContactBean{" +
                "iconId=" + iconId +
                ", title='" + title + '\'' +
                ", phoneNum='" + phoneNum + '\'' +
                ", descriptor='" + descriptor + '\'' +
                ", firstHeadLetter='" + firstHeadLetter + '\'' +
                ", headLetterNum='" + headLetterNum + '\'' +
                '}';
    }
}
第四整個布局activity_main.xml:

 

 



    
    
    
        
        
    

第五如何獲取手機中的聯系人信息:
主要思想就是通過android的中的四大組件之一ContentProvider來獲取,這個很簡單就不多做說明直接上代碼,最後別忘記加上兩個權限分別是讀、寫手機聯系人的權限:
權限:


獲取手機聯系人的代碼(我將它封裝成一個類中的方法並且直接返回為我們的ContactBean類集合,可以直接用來裝載adapter。使用起來很方便):

 

 

package com.mikyou.myguardian.service;

import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;

import com.mikyou.myguardian.bean.ContactBean;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by mikyou on 16-7-19.
 * 用於返回讀取到聯系人的集合
 */
public class ContactInfoService {
    private Context context;

    public ContactInfoService(Context context) {
        this.context = context;
    }
    public List getContactList(){

        List mContactBeanList=new ArrayList<>();
        ContactBean mContactBean=null;
        ContentResolver mContentResolver=context.getContentResolver();
        Uri uri=Uri.parse("content://com.android.contacts/raw_contacts");
        Uri dataUri=Uri.parse("content://com.android.contacts/data");

        Cursor cursor =mContentResolver.query(uri,null,null,null,null);
        while (cursor.moveToNext()){
          mContactBean=new ContactBean();
            String id=cursor.getString(cursor.getColumnIndex("_id"));
            String title=cursor.getString(cursor.getColumnIndex("display_name"));//獲取聯系人姓名
            String firstHeadLetter=cursor.getString(cursor.getColumnIndex("phonebook_label"));//這個字段保存了每個聯系人首字的拼音的首字母
            mContactBean.setTitle(title);
            mContactBean.setFirstHeadLetter(firstHeadLetter);

            Cursor dataCursor=mContentResolver.query(dataUri,null,"raw_contact_id= ?",new String[]{id},null);
            while(dataCursor.moveToNext()){
                String type=dataCursor.getString(dataCursor.getColumnIndex("mimetype"));
                if (type.equals("vnd.android.cursor.item/phone_v2")){//如果得到的mimeType類型為手機號碼類型才去接收
                    String phoneNum=dataCursor.getString(dataCursor.getColumnIndex("data1"));//獲取手機號碼
                    mContactBean.setPhoneNum(phoneNum);
                }
            }
            dataCursor.close();
            if (mContactBean.getTitle()!=null&&mContactBean.getPhoneNum()!=null){
                mContactBeanList.add(mContactBean);
            }

        }
        cursor.close();
        return mContactBeanList;
    }
}
第六,就是實現聯系人的ListView大家可能會看到這個和我們平時的看到的ListView有些不一樣,因為在此次聯系人的ListView中還有"A","B","C","D"...這小的字母item這個主要是將相同聯系人的第一個字的拼音的首字母放在一起。那怎麼去實現這樣的一個ListView呢?
這裡:我想了一個的辦法就是每個ListView的item項目的布局中都包含一個字母索引項目,也就是每一個聯系人的頂部都有一個字母索引項目用於顯示該聯系人
的首字的拼音的首字母,然後將我們集合中的對象按照首字母來排序,那麼集合中的聯系人對象將會是按照A到Z排序並且為A的聯系人放在一起,為B放在一起。可是由於我們的每個item都包含一個字母索引項,所以我們需要將相同字母的索引項去掉並且只保留一個且為第一個的該類字母的索引項即可。如果做到這一點呢???其實仔細想下也不難,由於我們的集合是已經按照字母大小排好順序的,並且首字母為A為一堆,首字母為B為一堆,首字母為C的為一堆...
那麼我們就去遍歷直接整個集合,用當前的item中的首字母去匹配上一個item中的首字母如果相同則表示是同一堆字母,就可以直接把該item中的頂部的標示的字母索引項中的內容設置為""空字符,並且把該索引項的Visibilty設置為GONE,如果不等就說明將有新的字母堆產生,而且是該堆中的第一個字母項,這時候我們就需要用一個Map集合alphaIndexer將他們保存起來,key為字母,value為該字母在集合中的下標,並且把該索引項的Visibilty設置為Visible。並且還得另外用一個集合selections保存該字母,為什麼需要用一個集合保存該字母呢?主要用於這麼一個需求就是:當我們去點擊右邊浮動的索引項列表中的字母時候,如果點擊的字母不在我們sleections集合中的話,就不會觸發彈出字母顯示框,這也很容易理解就是我的聯系人列表中根本就沒有以我點擊的字母為首字母的拼音的聯系人。所以這個selections集合就顯得尤為關鍵了,它可謂是浮動列表點擊的字母與聯系人列表實現聯動的核心橋梁和媒介。

具體看該ListView的Adapter:
package com.mikyou.myguardian.adapter;

import android.content.Context;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

import com.mikyou.adapter.CommonAdapter;
import com.mikyou.myguardian.R;
import com.mikyou.myguardian.bean.ContactBean;
import com.mikyou.tools.ViewHolder;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by mikyou on 16-7-19.
 */
public class TestContactListAdapter extends CommonAdapter {
    private final int VIEW_TYPE=3;
    private Map alphaIndexer;
    private List sections;
    private List listBeans;
    private OnGetAlphaIndexerAndSectionsListener listener;
    private boolean flag;//標志用於只執行一次代碼
    public TestContactListAdapter(Context context, List listBeans, int layoutId) {
        super(context, listBeans, layoutId);
        this.listBeans=listBeans;
        alphaIndexer=new HashMap<>();
        sections=new ArrayList<>();
        for (int i = 0; i =0?listBeans.get(i-1).getFirstHeadLetter():"";
            if (!previewAlpha.equals(currentAlpha)){
                String firstAlpha=listBeans.get(i).getFirstHeadLetter();
                alphaIndexer.put(firstAlpha,i);
                sections.add(firstAlpha);
            }

        }

    }

    @Override
    public int getItemViewType(int position) {
         int type=0;
        if (position==0){
            type=2;
        }else if (position==1){
            type=1;
        }
        return type;
    }

    @Override
    public int getCount() {
        //注意:為什麼沒有直接把回調方法的調用寫在構造器中呢?因為構造器只會調用一次,當第一次調用listener的時候是為空的
        //而要初始化listener對象,則需要先去創建對象再去通過對象調用set方法來初始化這個listener對象,再去new對象的時候又要去用到listener產生了矛盾
        //所以放在getCount中調用,只會調用一次,符合需求
        if (!flag){
            if (listener!=null){
                listener.getAlphaIndexerAndSectionsListner(alphaIndexer,sections);
            }
            flag=true;
        }

        return listBeans.size();

    }

    @Override
    public int getViewTypeCount() {
        return VIEW_TYPE;
    }

    @Override
    public void convert(ViewHolder viewHolder, ContactBean contactBean) {

        int viewType=getItemViewType(viewHolder.getmPosition());
        ImageView iv=viewHolder.getView(R.id.contact_icon_id);
        iv.setImageResource(R.mipmap.contact_user);
        viewHolder.setText(R.id.contact_title,contactBean.getTitle()).setText(R.id.contact_phone_num,contactBean.getPhoneNum());



        if (viewHolder.getmPosition()>=1){
            String currentAlpha=listBeans.get(viewHolder.getmPosition()).getFirstHeadLetter();
            String previewAlpha=listBeans.get(viewHolder.getmPosition()-1).getFirstHeadLetter();
            if (!previewAlpha.equals(currentAlpha)){//不相等表示有新的字母項產生且為該類字母堆中的第一個字母索引項
                viewHolder.getView(R.id.first_alpha).setVisibility(View.VISIBLE);//把新的字母列表項設置VISIBlE
                TextView tv= viewHolder.getView(R.id.first_alpha);
                tv.setText(currentAlpha);
            }else {//表示沒有新的字母堆出現,也就說明該item是屬於同類字母堆中且不是第一個,那麼就需要將這個索引項設置GONE
                viewHolder.getView(R.id.first_alpha).setVisibility(View.GONE);
            }
        }


    }
    public void setOnGetAlphaIndeserAndSectionListener(OnGetAlphaIndexerAndSectionsListener listener){
        this.listener=listener;
    }

    public interface OnGetAlphaIndexerAndSectionsListener{
        public void getAlphaIndexerAndSectionsListner(MapalphaIndexer,Listsections);

    }
}
第七該ListView的Item布局:


    
    

        
        
        
    

第八整個Activity的實現:

 

 

package com.mikyou.contactdemo;

import android.content.Context;
import android.graphics.PixelFormat;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ListView;
import android.widget.TextView;

import com.mikyou.contactdemo.adapter.TestContactListAdapter;
import com.mikyou.contactdemo.bean.ContactBean;
import com.mikyou.contactdemo.myview.MikyouLetterListView;
import com.mikyou.contactdemo.service.ContactInfoService;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

public class MainActivity extends AppCompatActivity implements TestContactListAdapter.OnGetAlphaIndexerAndSectionsListener{
    private List mContactBeanList;//所有聯系人集合
    private ListView mContactListView;//聯系人ListView
    private MikyouLetterListView mLetterListView;//字母表
    private TextView overLayout;//彈出對話框
    private OverlayThread overlayThread;
    private Map alphaIndexer;// 存放存在的漢語拼音首字母和與之對應的列表位置
    private Handler handler;
    private TestContactListAdapter adapter;
    private List sections;// 存放存在的漢語拼音首字母
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initData();
        initView();
        initOverlay();
    }

    private void initView() {
        registerAllViewIds();


        registerAllViewAdapters();


        registerAllViewEvents();
    }

    private void registerAllViewIds() {
  mContactListView= (ListView) findViewById(R.id.id_listview);
        mLetterListView= (MikyouLetterListView) findViewById(R.id.id_letterview);
    }

    private void registerAllViewAdapters() {
        adapter=new TestContactListAdapter(this,mContactBeanList,R.layout.contact_list_item);
        adapter.setOnGetAlphaIndeserAndSectionListener(this);

        mContactListView.setAdapter(adapter);

    }

    private void registerAllViewEvents() {
        mLetterListView.setOnTouchingLetterChangedListener(new LetterListViewListener());
    }

    private void initData() {
        //alphaIndexer=new HashMap<>();
        handler=new Handler();
        overlayThread=new OverlayThread();
        ContactInfoService mContactInfoService=new ContactInfoService(this);
        mContactBeanList=mContactInfoService.getContactList();//返回手機聯系人對象集合
        //按拼音首字母表排序
        Collections.sort(mContactBeanList,comparator);
    }

    @Override
    public void getAlphaIndexerAndSectionsListner(Map alphaIndexer, List sections) {
        this.alphaIndexer=alphaIndexer;
        this.sections=sections;
        Log.d("list",alphaIndexer.toString()+"\n"+sections.toString());
    }

    /**
     * @Mikyou
     * 字母列表點擊滑動監聽器事件
     * */
    private class LetterListViewListener implements
            MikyouLetterListView.OnTouchingLetterChangedListener {

        @Override
        public void onTouchingLetterChanged(final String s) {
            if (alphaIndexer.get(s) != null) {//判斷當前選中的字母是否存在集合中
                int position = alphaIndexer.get(s);//如果存在集合中則取出集合中該字母對應所在的位置,再利用對應的setSelection,就可以實現點擊選中相應字母,然後聯系人就會定位到相應的位置
                mContactListView.setSelection(position);
                overLayout.setText(s);
                overLayout.setVisibility(View.VISIBLE);
                handler.removeCallbacks(overlayThread);
                // 延遲一秒後執行,讓overlay為不可見
                handler.postDelayed(overlayThread, 1500);
            }
        }

    }
    /**
     * @mikyou
     * 初始化漢語拼音首字母彈出提示框
     * */
    private void initOverlay() {
        LayoutInflater inflater = LayoutInflater.from(this);
        overLayout = (TextView) inflater.inflate(R.layout.overlay, null);
        overLayout.setVisibility(View.INVISIBLE);
        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_APPLICATION,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                        | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
                PixelFormat.TRANSLUCENT);
        WindowManager windowManager =
                (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        windowManager.addView(overLayout, lp);
    }
    /**
     * @Mikyou
     * 首字母按a-z排序
     * */
    Comparator comparator=new Comparator() {
        @Override
        public int compare(ContactBean t1, ContactBean t2) {
            String a=t1.getFirstHeadLetter();
            String b=t2.getFirstHeadLetter();
            int flag=a.compareTo(b);
            if (flag==0){
                return a.compareTo(b);
            }else{
                return flag;
            }
        }
    };
    /**
     * @Mikyou
     * 設置overlay不可見
     * */
    private class OverlayThread implements Runnable{

        @Override
        public void run() {
            overLayout.setVisibility(View.GONE);
        }
    }
}
到這裡就談得差不多了,這個很常用,准備給自己以後的項目中繼續用。
最後運行的結果(這個gif可能錄不是很清楚,因為用的linux系統聽熱心網友說用recordmydesktop,但是經本人測試感覺使用起來很麻煩,而且效果不是很好,如果有小伙伴推薦一下在linux下的錄制軟件,請下面留言,將感激不盡):

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved