您的位置:首页 > 移动开发 > 微信开发

自定义快速索引,仿微信好友查询列表

2015-12-31 13:53 465 查看

自定义视图,快速索引

先从自定义控件代码来看吧

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;

/**
* 自定义View 快速索引
* @author 李帅帅
*
*/
public class QuickIndexView extends View {
public QuickIndexView(Context context, AttributeSet attrs) {
super(context, attrs);
paint = new Paint();
paint.setAntiAlias(true);
}

private float itemWidth;// item的宽度
private float itemHight;// item的高度

private String[] indexArr = { "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 Paint paint;

/**
* 测量
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
itemWidth = this.getWidth();
itemHight = this.getHeight() / 26f;
}

/**
* 画图
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (int i = 0; i < indexArr.length; i++) {
if (i != index) {// 如果i不等于选中的item时
paint.setColor(Color.BLACK);
paint.setTextSize(16);
} else {
paint.setColor(Color.RED);// 当前操作的字母
paint.setTextSize(25);
}
String word = indexArr[i];
// 得到word的宽高
Rect bounds = new Rect();
paint.getTextBounds(word, 0, word.length(), bounds);
int wordWidth = bounds.width();
int wordHight = bounds.height();
// 定义左下角的坐标
float x = itemWidth / 2 - wordWidth / 2;
float y = itemHight / 2 + wordHight / 2 + i * itemHight;
// 画出文本
canvas.drawText(word, x, y, paint);
}
}

private int index = -1;// 操作的字母下标

@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:// 按下
case MotionEvent.ACTION_MOVE:// 移动
float eventY = event.getY();
int eventindex = (int) (eventY / itemHight);
if (index != eventindex) {// 如果操作的index变化了
// 强制更新
invalidate();
index = eventindex;
// 通知activity更新textView
if (onIndexChangeListener != null) {
if(index<26&&index>0){
onIndexChangeListener.OnIndexChanged(indexArr[index]);
}
}
}
break;
case MotionEvent.ACTION_UP:
index = -1;
invalidate();
//当离开的时候
if (onIndexChangeListener != null) {
//              onIndexChangeListener.OnUp();
}
break;
default:
break;
}
return true;// 消费
}

/**
* 定义一个接口
*
* @author 李帅帅
*/
private OnIndexChangeListener onIndexChangeListener;

public interface OnIndexChangeListener {
// 当操作的下标改变时,按下时调用
public void OnIndexChanged(String word);
//      //当离开时调用
//      public void OnUp();
}

public void setOnIndexChangeListener(OnIndexChangeListener onIndexChangeListener) {
this.onIndexChangeListener = onIndexChangeListener;
}

}


第一步我们写一个类来继承View 然后在重写测量方法。再次方法中获得item的宽高

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
itemWidth = this.getWidth();
itemHight = this.getHeight() / 26f;
}


第二步:就到我们从写绘制的方法了,在此方法中我们根据选中角标的位置来让绘制字母颜色,以及字母的宽高

private int index = -1;// 操作的字母下标
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (int i = 0; i < indexA
fc23
rr.length; i++) {
if (i != index) {// 如果i不等于选中的item时
paint.setColor(Color.BLACK);
paint.setTextSize(16);
} else {
paint.setColor(Color.RED);// 当前操作的字母
paint.setTextSize(25);
}
String word = indexArr[i];
// 得到word的宽高
Rect bounds = new Rect();
paint.getTextBounds(word, 0, word.length(), bounds);
int wordWidth = bounds.width();
int wordHight = bounds.height();
// 定义左下角的坐标
float x = itemWidth / 2 - wordWidth / 2;
float y = itemHight / 2 + wordHight / 2 + i * itemHight;
// 画出文本
canvas.drawText(word, x, y, paint);
}
}


第三步: 也是最为重要的一步,就是onTouchEvent此方法了。在此方法中我们会判断down move up ,当我们按下和移动的时候动态的获得Y/itemheight ,这就是我们选中字母的坐标,如果选中的角标变化了,那么就调用这个invalidate();方法,让其强制重绘,当然在此方法中我们会写一个接口,供页面回调,也是参照源码监听来写的,up的时候也让其强制重绘,记得角标改成非法值.

@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:// 按下
case MotionEvent.ACTION_MOVE:// 移动
float eventY = event.getY();
int eventindex = (int) (eventY / itemHight);
if (index != eventindex) {// 如果操作的index变化了
// 强制更新
invalidate();
index = eventindex;
// 通知activity更新textView
if (onIndexChangeListener != null) {
if(index<26&&index>0){
onIndexChangeListener.OnIndexChanged(indexArr[index]);
}
}
}
break;
case MotionEvent.ACTION_UP:
index = -1;
invalidate();
//当离开的时候
if (onIndexChangeListener != null) {
//              onIndexChangeListener.OnUp();
}
break;
default:
break;
}
return true;// 消费
}


最后这个是我们写的接口

/**
* 定义一个接口
*
* @author 李帅帅
*/
private OnIndexChangeListener onIndexChangeListener;

public interface OnIndexChangeListener {
// 当操作的下标改变时,按下时调用
public void OnIndexChanged(String word);
//      //当离开时调用
//      public void OnUp();
}

public void setOnIndexChangeListener(OnIndexChangeListener onIndexChangeListener) {
this.onIndexChangeListener = onIndexChangeListener;
}


MainActivity的代码附上

/**
* 页面一
*
* @author admin
*
*/
public class OneFragment extends Fragment {

private TextView mTextView;
private QuickIndexView mQIV;
private ListView mListView;
private List<Friend> data = new ArrayList<Friend>();
private FriendAdapter adapter;
private Context mContext;

private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
// 隐藏自己
mTextView.setVisibility(View.GONE);
}
};

public OneFragment(FragmentActivity mContext) {
this.mContext = mContext;
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_one, container, false);
initData();
initViews(view);
setListener();
return view;
}

/**
* 初始化试图
*/
private void initViews(View view) {
// 初始化
mTextView = (TextView) view.findViewById(R.id.tv_main_word);
mListView = (ListView) view.findViewById(R.id.lv_main);
mQIV = (QuickIndexView) view.findViewById(R.id.qiv_main);
// 显示列表
adapter = new FriendAdapter(mContext, data);
mListView.setAdapter(adapter);
}

/**
* 设置监听
*/
private void setListener() {
// 设置监听
mQIV.setOnIndexChangeListener(new QuickIndexView.OnIndexChangeListener() {

@Override
public void OnIndexChanged(String word) {
mTextView.setText(word);
mTextView.setVisibility(View.VISIBLE);

// 移除未处理的消息
handler.removeCallbacksAndMessages(null);
handler.sendEmptyMessageDelayed(1, 1000);

// 遍历data
for (int i = 0; i < data.size(); i++) {
// 得到首字母
String firstPinYin = data.get(i).getPinyin().substring(0, 1);
if (word.equals(firstPinYin)) {
mListView.setSelection(i);
return;
}
}
}
});
//设置点击监听
mListView.setOnItemClickListener(new OnItemClickListener() {

@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
Toast.makeText(mContext, data.get(arg2).getName(), 0).show();
}
});
}

/**
* 准备数据
*/
private void initData() {
data.add(new Friend("张晓飞"));
data.add(new Friend("杨光福"));
data.add(new Friend("胡继群"));
data.add(new Friend("刘畅"));
data.add(new Friend("钟泽兴"));
data.add(new Friend("尹革新"));
data.add(new Friend("安传鑫"));
data.add(new Friend("张骞壬"));
data.add(new Friend("温松"));
data.add(new Friend("李凤秋"));
data.add(new Friend("刘甫"));
data.add(new Friend("娄全超"));
data.add(new Friend("张猛"));
data.add(new Friend("王英杰"));
data.add(new Friend("李振南"));
data.add(new Friend("孙仁政"));
data.add(new Friend("唐春雷"));
data.add(new Friend("牛鹏伟"));
data.add(new Friend("姜宇航"));
data.add(new Friend("刘挺"));
data.add(new Friend("张洪瑞"));
data.add(new Friend("张建忠"));
data.add(new Friend("侯亚帅"));
data.add(new Friend("刘帅"));
data.add(new Friend("乔竞飞"));
data.add(new Friend("徐雨健"));
data.add(new Friend("吴亮"));
data.add(new Friend("王兆霖"));
data.add(new Friend("阿三"));
Collections.sort(data);
}

}


注意:我这里是接着上一篇架构的第一个OneFragment写的,如果是Activity页面,那么onCreateView就相当于onCreate方法,就是加载一个布局,然后其他类似.

fragment_one.Xml 代码,就是main_activity.xml

<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"
tools:context="${relativePackage}.${activityClass}" >

<ListView
android:id="@+id/lv_main"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ListView>

<com.example.fragmenttest.views.QuickIndexView
android:id="@+id/qiv_main"
android:layout_width="30dp"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:background="@android:color/transparent" />

<TextView
android:id="@+id/tv_main_word"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:background="#66666666"
android:text="A"
android:textColor="#EADAA9"
android:textSize="40sp"
android:gravity="center"
android:visibility="gone"/>

</RelativeLayout>


FriendAdapter代码

import java.util.List;

import com.example.fragmenttest.R;
import com.example.fragmenttest.model.Friend;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

public class FriendAdapter extends BaseAdapter {
private List<Friend> mDatas;
private Context mContext;

public FriendAdapter(Context mContext, List<Friend> data) {
mDatas = data;
this.mContext = mContext;
}

@Override
public int getCount() {
return mDatas.size();
}

@Override
public Object getItem(int position) {
return mDatas.get(position);
}

@Override
public long getItemId(int position) {
return 0;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
holder = new ViewHolder();
convertView = View.inflate(mContext, R.layout.item_one_fragment, null);
holder.wordTV = (TextView) convertView .findViewById(R.id.tv_main_word);
holder.nameTV = (TextView) convertView .findViewById(R.id.tv_item_name);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
Friend friend = mDatas.get(position);
String word = friend.getPinyin().substring(0, 1);
holder.wordTV.setText(word);
holder.nameTV.setText(friend.getName());

// 如果下标为0,那么让其显示
if (position == 0) {
holder.wordTV.setVisibility(View.VISIBLE);
} else {
// 取出上一个friend,并得到第一个word
String preWord = mDatas.get(position - 1).getPinyin().substring(0, 1);
if (word.equals(preWord)) {// 如果相同,那么就隐藏
holder.wordTV.setVisibility(View.GONE);
} else {// 如果不同,显示
holder.wordTV.setVisibility(View.VISIBLE);
}

}
return convertView;
}

class ViewHolder {
public TextView wordTV;
public TextView nameTV;
}

}


item_one_fragment布局代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<TextView
android:id="@+id/tv_main_word"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="A"
android:textSize="18sp"
android:background="#66666666"
android:padding="5dp"/>
<TextView
android:id="@+id/tv_item_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="阿三"
android:textSize="18sp"
android:padding="5dp"/>

</LinearLayout>


忘记了一个重要的工具类,中文转换为字母,当然我们需要下载一个pinyin4j-2.5.0.jar包

import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;

/**
* 将汉字转换为拼音
* @author 李帅帅
*
*/
public class PinYinUtils {
/**
* 得到指定汉字的拼音
* 注意:不应该被频繁调用,它消耗一定内存
* @param hanzi
* @return
*/
public static String getPinYin(String hanzi){
String pinyin = "";

HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();//控制转换是否大小写,是否带音标
format.setCaseType(HanyuPinyinCaseType.UPPERCASE);//大写
format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);

//由于不能直接对多个汉字转换,只能对单个汉字转换
char[] arr = hanzi.toCharArray();
for (int i = 0; i < arr.length; i++) {
if(Character.isWhitespace(arr[i]))continue;//如果是空格,则不处理,进行下次遍历

//汉字是2个字节存储,肯定大于127,所以大于127就可以当为汉字转换
if(arr[i]>127){
try {
//由于多音字的存在,单 dan shan
String[] pinyinArr = PinyinHelper.toHanyuPinyinStringArray(arr[i], format);

if(pinyinArr!=null){
pinyin += pinyinArr[0];
}else {
pinyin += arr[i];
}
} catch (BadHanyuPinyinOutputFormatCombination e) {
e.printStackTrace();
//不是正确的汉字
pinyin += arr[i];
}
}else {
//不是汉字,
pinyin += arr[i];
}
}
return pinyin;
}
}






希望能够帮到大家,谢谢

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: