废话不多说
首先上效果图:
要做的这样的效果 首先导入一个pinyin包
compile 'com.belerweb:pinyin4j:2.5.1'
接下来做一些准备工作吧
主页面的Xml
里面用到了自定义的 SideBarView
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:poplar="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#d5d5d5">
<TextView
android:id="@+id/tv_friends_toolbar"
android:layout_width="match_parent"
android:layout_height="52dp"
android:background="#41c2fc"
android:gravity="center"
android:text="通讯录"
android:textColor="#fff"
android:textSize="20sp"/>
<ListView
android:id="@+id/lv_friends_listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/tv_friends_toolbar"/>
<com.cooltone.demo.SideBarView
android:id="@+id/sbv_friends_bar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/tv_friends_toolbar"
android:layout_marginBottom="5dp"
android:layout_marginTop="5dp"
poplar:additionalTipOffset="40dp"
poplar:fontColor="#6e6e6e"
poplar:maxBezierHeight="150dp"
poplar:maxBezierWidth="180dp"
poplar:maxFontSize="60"
poplar:minFontSize="32"
poplar:tipFontColor="#41c2fc"
poplar:tipFontSize="72"
poplar:widthOffset="15dp"/>
<TextView
android:id="@+id/tv_friends_center"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_below="@id/tv_friends_toolbar"
android:layout_centerInParent="true"
android:background="@drawable/sidebar_background"
android:gravity="center"
android:text="A"
android:textColor="#fff"
android:textSize="36sp"
android:visibility="gone"/>
</RelativeLayout>
上面包红没关系啊 一步步来,记得一会自定义View 要换包名。接下来是listView 条目 布局
<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_friend_title"
android:layout_width="match_parent"
android:layout_height="20dp"
android:background="#919191"
android:gravity="center_vertical"
android:paddingLeft="20dp"
android:text="A"
android:textSize="14sp"/>
<TextView
android:id="@+id/tv_friend_name"
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="#fff"
android:gravity="center_vertical"
android:paddingLeft="20dp"
android:text="宋江"
android:textColor="#00f"
android:textSize="16sp"/>
</LinearLayout>
接下来什么呢 ,在drawable文件下 建一个背景吧 sidebar_background
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!-- 通讯录 -->
<corners android:radius="25dp"/>
<solid android:color="#66000000"/>
</shape>
接下来就是重要人物出场了
建 SideBarView 继承 View 写我们的索引控件
里面的东西自己想研究下的话, 可以自己研究,本人也不是很懂,用了贝塞尔曲线
/**
* 作者:CoolTone
* 描述:右侧导航栏字母列表
*/
public class SideBarView extends View {
private OnTouchLetterChangedListener mListener;
public interface OnTouchLetterChangedListener {
void onTouchLetterChanged(String letter);
}
public void setOnTouchLetterChangedListener(OnTouchLetterChangedListener listener) {
this.mListener = listener;
}
// 向右偏移多少画字符, default 30
float mWidthOffset = 30.0f;
// 最小字体大小
int mMinFontSize = 24;
// 最大字体大小
int mMaxFontSize = 48;
// 提示字体大小
int mTipFontSize = 52;
// 提示字符的额外偏移
float mAdditionalTipOffset = 20.0f;
// 贝塞尔曲线控制的高度
float mMaxBezierHeight = 150.0f;
// 贝塞尔曲线单侧宽度
float mMaxBezierWidth = 240.0f;
// 贝塞尔曲线单侧模拟线量
int mMaxBezierLines = 32;
// 列表字符颜色
int mFontColor = 0xffffffff;
// 提示字符颜色
int mTipFontColor = 0xffd33e48;
private final String[] ConstChar = {"#", "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 mChooseIndex = -1;
Paint mPaint = new Paint();
PointF mTouch = new PointF();
PointF[] mBezier1;
PointF[] mBezier2;
float mLastOffset[] = new float[ConstChar.length]; // 记录每一个字母的x方向偏移量, 数字<=0
PointF mPointF = new PointF();
Scroller mScroller;
boolean mAnimating = false;
float mAnimationOffset;
boolean mHideAnimation = false;
int mAlpha = 255;
Handler mHideWaitingHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 1) {
mHideAnimation = true;
mAnimating = false;
SideBarView.this.invalidate();
return;
}
super.handleMessage(msg);
}
};
public SideBarView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initData(context, attrs);
}
public SideBarView(Context context, AttributeSet attrs) {
super(context, attrs);
initData(context, attrs);
}
public SideBarView(Context context) {
super(context);
initData(null, null);
}
private void initData(Context context, AttributeSet attrs) {
if (context != null && attrs != null) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FancyIndexer, 0, 0);
mWidthOffset = a.getDimension(R.styleable.FancyIndexer_widthOffset, mWidthOffset);
// 最小
mMinFontSize = a.getInteger(R.styleable.FancyIndexer_minFontSize, mMinFontSize);
// 最大
mMaxFontSize = a.getInteger(R.styleable.FancyIndexer_maxFontSize, mMaxFontSize);
mTipFontSize = a.getInteger(R.styleable.FancyIndexer_tipFontSize, mTipFontSize);
mMaxBezierHeight = a.getDimension(R.styleable.FancyIndexer_maxBezierHeight, mMaxBezierHeight);
mMaxBezierWidth = a.getDimension(R.styleable.FancyIndexer_maxBezierWidth, mMaxBezierWidth);
mMaxBezierLines = a.getInteger(R.styleable.FancyIndexer_maxBezierLines, mMaxBezierLines);
mAdditionalTipOffset = a.getDimension(R.styleable.FancyIndexer_additionalTipOffset, mAdditionalTipOffset);
// 颜色
mFontColor = a.getColor(R.styleable.FancyIndexer_fontColor, mFontColor);
// 提示颜色
mTipFontColor = a.getColor(R.styleable.FancyIndexer_tipFontColor, mTipFontColor);
a.recycle();
}
mScroller = new Scroller(getContext());
mTouch.x = 0;
mTouch.y = -10 * mMaxBezierWidth;
mBezier1 = new PointF[mMaxBezierLines];
mBezier2 = new PointF[mMaxBezierLines];
calculateBezierPoints();
}
@Override
protected void onDraw(Canvas canvas) {
// 控件宽高
int height = getHeight();
int width = getWidth();
// 单个字母高度
float singleHeight = height / (float) ConstChar.length;
int workHeight = 0;
if (mAlpha == 0)
return;
mPaint.reset();
int saveCount = 0;
if (mHideAnimation) {
saveCount = canvas.save();
canvas.saveLayerAlpha(0, 0, width, height, mAlpha, Canvas.ALL_SAVE_FLAG);
}
for (int i = 0; i < ConstChar.length; i++) {
mPaint.setColor(mFontColor);
mPaint.setAntiAlias(true);
float xPos = width - mWidthOffset;
float yPos = workHeight + singleHeight / 2;
// float adjustX = adjustXPos( yPos, i == mChooseIndex );
// 根据当前字母y的位置计算得到字体大小
int fontSize = adjustFontSize(i, yPos);
mPaint.setTextSize(fontSize);
// 添加一个字母的高度
workHeight += singleHeight;
// 绘制字母
drawTextInCenter(canvas, ConstChar[i], xPos + ajustXPosAnimation(i, yPos), yPos);
// 绘制的字母和当前触摸到的一致, 绘制红色被选中字母
if (i == mChooseIndex) {
mPaint.setColor(mTipFontColor);
mPaint.setFakeBoldText(true);
mPaint.setTextSize(mTipFontSize);
yPos = mTouch.y;
float pos = 0;
if (mAnimating || mHideAnimation) {
pos = mPointF.x;
yPos = mPointF.y;
} else {
pos = xPos + ajustXPosAnimation(i, yPos) - mAdditionalTipOffset;
mPointF.x = pos;
mPointF.y = yPos;
}
drawTextInCenter(canvas, ConstChar[i], pos, yPos);
}
mPaint.reset();
}
if (mHideAnimation) {
canvas.restoreToCount(saveCount);
}
}
/**
* @param canvas 画板
* @param string 被绘制的字母
* @param xCenter 字母的中心x方向位置
* @param yCenter 字母的中心y方向位置
*/
private void drawTextInCenter(Canvas canvas, String string, float xCenter, float yCenter) {
Paint.FontMetrics fm = mPaint.getFontMetrics();
float fontHeight = mPaint.getFontSpacing();
float drawY = yCenter + fontHeight / 2 - fm.descent;
if (drawY < -fm.ascent - fm.descent)
drawY = -fm.ascent - fm.descent;
if (drawY > getHeight())
drawY = getHeight();
mPaint.setTextAlign(Paint.Align.CENTER);
canvas.drawText(string, xCenter, drawY, mPaint);
}
private int adjustFontSize(int i, float yPos) {
// 根据水平方向偏移量计算出一个放大的字号
float adjustX = Math.abs(ajustXPosAnimation(i, yPos));
int adjustSize = (int) ((mMaxFontSize - mMinFontSize) * adjustX / mMaxBezierHeight) + mMinFontSize;
return adjustSize;
}
/**
* x 方向的向左偏移量
*
* @param i 当前字母的索引
* @param yPos y方向的初始位置
* @return
*/
private float ajustXPosAnimation(int i, float yPos) {
float offset;
if (this.mAnimating || this.mHideAnimation) {
// 正在动画中或在做隐藏动画
offset = mLastOffset[i];
if (offset != 0.0f) {
offset += this.mAnimationOffset;
if (offset > 0)
offset = 0;
}
} else {
// 根据当前字母y方向位置, 计算水平方向偏移量
offset = adjustXPos(yPos);
// 当前触摸的x方向位置
float xPos = mTouch.x;
float width = getWidth() - mWidthOffset;
width = width - 60;
// 字母绘制时向左偏移量 进行修正, offset需要是<=0的值
if (offset != 0.0f && xPos > width)
offset += (xPos - width);
if (offset > 0)
offset = 0;
mLastOffset[i] = offset;
}
return offset;
}
private float adjustXPos(float yPos) {
float dis = yPos - mTouch.y; // 字母y方向位置和触摸时y值坐标的差值, 距离越小, 得到的水平方向偏差越大
if (dis > -mMaxBezierWidth && dis < mMaxBezierWidth) {
// 在2个贝赛尔曲线宽度范围以内 (一个贝赛尔曲线宽度是指一个山峰的一边)
// 第一段 曲线
if (dis > mMaxBezierWidth / 4) {
for (int i = mMaxBezierLines - 1; i > 0; i--) {
// 从下到上, 逐个计算
if (dis == -mBezier1[i].y) // 落在点上
return mBezier1[i].x;
// 如果距离dis落在两个贝塞尔曲线模拟点之间, 通过三角函数计算得到当前dis对应的x方向偏移量
if (dis > -mBezier1[i].y && dis < -mBezier1[i - 1].y) {
return (dis + mBezier1[i].y) * (mBezier1[i - 1].x - mBezier1[i].x) / (-mBezier1[i - 1].y + mBezier1[i].y) + mBezier1[i].x;
}
}
return mBezier1[0].x;
}
// 第三段 曲线, 和第一段曲线对称
if (dis < -mMaxBezierWidth / 4) {
for (int i = 0; i < mMaxBezierLines - 1; i++) {
// 从上到下
if (dis == mBezier1[i].y) // 落在点上
return mBezier1[i].x;
// 如果距离dis落在两个贝塞尔曲线模拟点之间, 通过三角函数计算得到当前dis对应的x方向偏移量
if (dis > mBezier1[i].y && dis < mBezier1[i + 1].y) {
return (dis - mBezier1[i].y) * (mBezier1[i + 1].x - mBezier1[i].x) / (mBezier1[i + 1].y - mBezier1[i].y) + mBezier1[i].x;
}
}
return mBezier1[mMaxBezierLines - 1].x;
}
// 第二段 峰顶曲线
for (int i = 0; i < mMaxBezierLines - 1; i++) {
if (dis == mBezier2[i].y)
return mBezier2[i].x;
// 如果距离dis落在两个贝塞尔曲线模拟点之间, 通过三角函数计算得到当前dis对应的x方向偏移量
if (dis > mBezier2[i].y && dis < mBezier2[i + 1].y) {
return (dis - mBezier2[i].y) * (mBezier2[i + 1].x - mBezier2[i].x) / (mBezier2[i + 1].y - mBezier2[i].y) + mBezier2[i].x;
}
}
return mBezier2[mMaxBezierLines - 1].x;
}
return 0.0f;
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
final int action = event.getAction();
final float y = event.getY();
final int oldmChooseIndex = mChooseIndex;
final OnTouchLetterChangedListener listener = mListener;
final int c = (int) (y / getHeight() * ConstChar.length);
switch (action) {
case MotionEvent.ACTION_DOWN:
if (this.getWidth() > mWidthOffset) {
if (event.getX() < this.getWidth() - mWidthOffset)
return false;
}
mHideWaitingHandler.removeMessages(1);
mScroller.abortAnimation();
mAnimating = false;
mHideAnimation = false;
mAlpha = 255;
mTouch.x = event.getX();
mTouch.y = event.getY();
if (oldmChooseIndex != c && listener != null) {
if (c > 0 && c < ConstChar.length) {
listener.onTouchLetterChanged(ConstChar[c]);
mChooseIndex = c;
}
}
invalidate();
break;
case MotionEvent.ACTION_MOVE:
mTouch.x = event.getX();
mTouch.y = event.getY();
invalidate();
if (oldmChooseIndex != c && listener != null) {
if (c >= 0 && c < ConstChar.length) {
listener.onTouchLetterChanged(ConstChar[c]);
mChooseIndex = c;
}
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mTouch.x = event.getX();
mTouch.y = event.getY();
mScroller.startScroll(0, 0, (int) mMaxBezierHeight, 0, 500);
mAnimating = true;
postInvalidate();
break;
}
return true;
}
@Override
public void computeScroll() {
super.computeScroll();
if (mScroller.computeScrollOffset()) {
if (mAnimating) {
float x = mScroller.getCurrX();
mAnimationOffset = x;
} else if (mHideAnimation) {
mAlpha = 255 - mScroller.getCurrX();
}
invalidate();
} else if (mScroller.isFinished()) {
if (mAnimating) {
mHideWaitingHandler.sendEmptyMessage(1);
} else if (mHideAnimation) {
mHideAnimation = false;
this.mChooseIndex = -1;
mTouch.x = -10000;
mTouch.y = -10000;
}
}
}
/**
* 计算出所有贝塞尔曲线上的点
* 个数为 mMaxBezierLines * 2 = 64
*/
private void calculateBezierPoints() {
PointF mStart = new PointF(); // 开始点
PointF mEnd = new PointF(); // 结束点
PointF mControl = new PointF(); // 控制点
// 计算第一段红色部分 贝赛尔曲线的点
// 开始点
mStart.x = 0.0f;
mStart.y = -mMaxBezierWidth;
// 控制点
mControl.x = 0.0f;
mControl.y = -mMaxBezierWidth / 2;
// 结束点
mEnd.x = -mMaxBezierHeight / 2;
mEnd.y = -mMaxBezierWidth / 4;
mBezier1[0] = new PointF();
mBezier1[mMaxBezierLines - 1] = new PointF();
mBezier1[0].set(mStart);
mBezier1[mMaxBezierLines - 1].set(mEnd);
for (int i = 1; i < mMaxBezierLines - 1; i++) {
mBezier1[i] = new PointF();
mBezier1[i].x = calculateBezier(mStart.x, mEnd.x, mControl.x, i / (float) mMaxBezierLines);
mBezier1[i].y = calculateBezier(mStart.y, mEnd.y, mControl.y, i / (float) mMaxBezierLines);
}
// 计算第二段蓝色部分 贝赛尔曲线的点
mStart.y = -mMaxBezierWidth / 4;
mStart.x = -mMaxBezierHeight / 2;
mControl.y = 0.0f;
mControl.x = -mMaxBezierHeight;
mEnd.y = mMaxBezierWidth / 4;
mEnd.x = -mMaxBezierHeight / 2;
mBezier2[0] = new PointF();
mBezier2[mMaxBezierLines - 1] = new PointF();
mBezier2[0].set(mStart);
mBezier2[mMaxBezierLines - 1].set(mEnd);
for (int i = 1; i < mMaxBezierLines - 1; i++) {
mBezier2[i] = new PointF();
mBezier2[i].x = calculateBezier(mStart.x, mEnd.x, mControl.x, i / (float) mMaxBezierLines);
mBezier2[i].y = calculateBezier(mStart.y, mEnd.y, mControl.y, i / (float) mMaxBezierLines);
}
}
/**
* 贝塞尔曲线核心算法
*
* @param start
* @param end
* @param control
* @param val
* @return 公式及动图, 维基百科: https://en.wikipedia.org/wiki/B%C3%A9zier_curve
* 中文可参考此网站: http://blog.csdn.net/likendsl/article/details/7852658
*/
private float calculateBezier(float start, float end, float control, float val) {
float t = val;
float s = 1 - t;
float ret = start * s * s + 2 * control * s * t + end * t * t;
return ret;
}
}
之后来,当然是善后啦 因为里面会包红呀!
接下来在values里面创建attrs文件
<!-- 通讯录 -->
<declare-styleable name="FancyIndexer">
<attr name="widthOffset" format="dimension"/>
<attr name="minFontSize" format="integer"/>
<attr name="maxFontSize" format="integer"/>
<attr name="tipFontSize" format="integer"/>
<attr name="maxBezierHeight" format="dimension"/>
<attr name="maxBezierWidth" format="dimension"/>
<attr name="maxBezierLines" format="integer"/>
<attr name="additionalTipOffset" format="dimension"/>
<attr name="fontColor" format="color"/>
<attr name="tipFontColor" format="color"/>
</declare-styleable>
做完这些估计就不会包红了吧! 因为我这写完了没有什么红 所以我也记不清了!
这里因为要给好友列表排序 当然少不了拼音 和 实体类
FriendEntity实体类
/**
* 作者: CoolTone
* 描述: 好友列表实体类
*/
public class FriendEntity implements Comparable<FriendEntity> {
private String name;
private String pinyin;
public FriendEntity() {
}
@Override
public int compareTo(FriendEntity another) {
return pinyin.compareTo(another.pinyin);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPinyin() {
return pinyin;
}
public void setPinyin(String pinyin) {
this.pinyin = pinyin;
}
@Override
public String toString() {
return "FriendEntity{" +
"name='" + name + '\'' +
", pinyin='" + pinyin + '\'' +
'}';
}
}
对于上面要说一句 不要忘了 很重要哦!排序用的
@Override
public int compareTo(FriendEntity another) {
return pinyin.compareTo(another.pinyin);
}
接下来 PinyinUtil 帮助类
/**
* 作者: CoolTone
* 描述: 通讯录 拼音 帮助类
*/
public class PinyinUtil {
/**
* 根据汉字获取对应的拼音
*
* @param str
* @return
*/
public static String getPinyin(String str) {
// 设置输出配置
HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
// 设置大写
format.setCaseType(HanyuPinyinCaseType.UPPERCASE);
// 设置不需要音调
format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
StringBuilder sb = new StringBuilder();
// 获取字符数组
char[] charArray = str.toCharArray();
for (int i = 0; i < charArray.length; i++) {
char c = charArray[i];
if (Character.isWhitespace(c)) { // 如果是空格, 跳过当前的循环
continue;
}
if (c > 128 || c < -127) { // 可能是汉字
try { // 根据字符获取对应的拼音
String s = PinyinHelper.toHanyuPinyinStringArray(c, format)[0];
sb.append(s);
} catch (BadHanyuPinyinOutputFormatCombination e) {
e.printStackTrace();
}
} else {
// ~!@#$%^&*()_+{}|:"<>?\/1234567890
// 不需要转换, 直接添加
// 根据字符获取对应的拼音
sb.append(c);
}
}
return sb.toString();
}
}
这个工具里面有注释就不多说了!
接下来是Adapter的工具类 因为本人比较喜欢用ListView 所以这个父类的Adapter 很有用
/**
* 作者: CoolTone
* 描述: 父类Adapter
*/
public abstract class SecondAdapter<T> extends BaseAdapter {
private List<T> mData; // 数据信息
private LayoutInflater mInflater;// 填充布局
private Context mContext; // 上下文
public SecondAdapter(Context context) {
mData = new ArrayList<>();
mInflater = LayoutInflater.from(context);
mContext = context;
}
@Override
public int getCount() {
return mData.size();
}
@Override
public T getItem(int position) {
return mData.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
public List<T> getData() {
return mData;
}
public LayoutInflater getInflater() {
return mInflater;
}
public Context getContext() {
return mContext;
}
/**
* 添加集合
*/
public void addAll(List<T> data) {
mData.addAll(data);
notifyDataSetChanged();
}
/**
* 清除集合
*/
public void clear() {
mData.clear();
notifyDataSetChanged();
}
}
然后就是写 FriendAdapter 主要赋值嘛
这里面要做一些逻辑处理:
比如判断是否是拼音,是否拼音的第一位等等
/**
* 作者: CoolTone
* 描述: 数据Adapter
*/
public class FriendAdapter extends SecondAdapter<FriendEntity> {
public FriendAdapter(Context context) {
super(context);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = getInflater().inflate(R.layout.item_friend, null);
}
ItemViewHolder holder = (ItemViewHolder) convertView.getTag();
if (holder == null) {
holder = new ItemViewHolder(convertView);
convertView.setTag(holder);
}
holder.bindView(position);
return convertView;
}
class ItemViewHolder {
private final TextView mName;
private final TextView mTitle;
public ItemViewHolder(View itemView) {
mName = ((TextView) itemView.findViewById(R.id.tv_friend_name));
mTitle = (TextView) itemView.findViewById(R.id.tv_friend_title);
}
public void bindView(int position) {
FriendEntity friend = getData().get(position);
String pinyin = friend.getPinyin();
if (!pinyin.isEmpty()) {
String s = String.valueOf(pinyin.charAt(0));
if ((s.charAt(0) <= 'Z' && s.charAt(0) >= 'A') || (s.charAt(0) <= 'z' && s.charAt(0) >= 'a')) {
oneYesLetter(position, friend, s);
} else {
oneNoLetter(position, friend, s);
}
}
}
// 第一位是否是字母 Y
private void oneYesLetter(int position, FriendEntity friend, String currentLetter) {
String indexStr = null;
if (position == 0) { // 如果是第一位
indexStr = currentLetter;
} else { // 获取上一个拼音
String preLetter = getData().get(position - 1).getPinyin().charAt(0) + "";
if (!TextUtils.equals(currentLetter, preLetter)) {
indexStr = currentLetter; // 当跟上一个不同时, 赋值, 显示
}
}
mTitle.setVisibility(indexStr == null ? View.GONE : View.VISIBLE);
mTitle.setText(indexStr);
mName.setText(friend.getName());
}
// 第一位是否是字母 N
private void oneNoLetter(int position, FriendEntity friend, String currentLetter) {
String indexStr = null;
if (position == 0) { // 如果是第一位
indexStr = currentLetter;
}
mTitle.setVisibility(indexStr == null ? View.GONE : View.VISIBLE);
mTitle.setText("#");
mName.setText(friend.getName());
}
}
}
这就完了! 但是还有写主程序呀!你逗我
/**
* 作者: CoolTone
* 描述: 好友列表
*/
public class MainActivity extends AppCompatActivity implements SideBarView.OnTouchLetterChangedListener {
private ArrayList<FriendEntity> mFriends;
private FriendAdapter mAdapter;
private ListView mListView;
private SideBarView mSideView;
private TextView mLetter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
setListener();
}
private void setListener() {
mSideView.setOnTouchLetterChangedListener(this);
}
private void initData() {
mFriends = new ArrayList<>();
mAdapter = new FriendAdapter(this);
mListView.setAdapter(mAdapter);
String[] names = new String[]{"逗霸最伟大", "鬧夠了就去吃藥", "破灭等于拥有", "贪恋剧情小丑",
"若隐若现", "我叫意志力", "龍飛鳳舞", "别拿爱情说宿命",
"青春帅气先森", "年华仅是无效信", "年华仅是无效信", "中国好同桌", "折磨",
"马子大", "不哭的理由", "唱歌跑调那叫范", "爱4太给力", "你与寂寞有染",};
for (int i = 0; i < names.length; i++) {
FriendEntity friend = new FriendEntity();
friend.setName(names[i]);
friend.setPinyin(PinyinUtil.getPinyin(names[i]));
mFriends.add(friend);
}
Collections.sort(mFriends); // 这里千万不能忘
mAdapter.addAll(mFriends);
mAdapter.notifyDataSetChanged();
}
private void initView() {
mListView = ((ListView) findViewById(R.id.lv_friends_listView));
mSideView = ((SideBarView) findViewById(R.id.sbv_friends_bar));
mLetter = ((TextView) findViewById(R.id.tv_friends_center));
}
@Override
public void onTouchLetterChanged(String letter) {
// showLetter(letter);
if (!mFriends.isEmpty()) {
for (int i = 0; i < mFriends.size(); i++) {
FriendEntity friend = mFriends.get(i);
String s = String.valueOf(friend.getPinyin().charAt(0));
if (TextUtils.equals(s, letter)) { // 匹配成功, 中断循环, 跳转到i位置
mListView.setSelection(i);
break;
}
}
}
}
// /**
// * 显示字母提示
// *
// * @param letter
// */
// protected void showLetter(String letter) {
// mLetter.setVisibility(View.VISIBLE);
// mLetter.setText(letter);
//
// // 取消掉刚刚所有的演示操作
// mHandler.removeCallbacksAndMessages(null);
// mHandler.postDelayed(new Runnable() {
// @Override
// public void run() {
// // 隐藏
// mCenter.setVisibility(View.GONE);
// }
// }, 500);
// }
}
嗯哼大功告成了吧! 反正我已经晕了 应该没有丢下东西才对
注意事项:好友列表数据 在给Adapter 添加数据之前千万不要忘了 Collections.sort(); 排序
for (int i = 0; i < names.length; i++) {
FriendEntity friend = new FriendEntity();
friend.setName(names[i]);
friend.setPinyin(PinyinUtil.getPinyin(names[i]));
mFriends.add(friend);
}
Collections.sort(mFriends); // 这里千万不能忘
mAdapter.addAll(mFriends);
mAdapter.notifyDataSetChanged();
Demo下载地址:http://download.csdn.net/detail/qq_35352552/9797827