创新源于模仿之二:美化ListView的尝试
2017-09-18 15:03
330 查看
今天继续,模仿MIUI做那个Contacts的ListView,如下图:
其实可以这样归纳一下我们要做的事情:
1. 按首字母分组,显示一个分组的标签头。
2. 在右边做一个全字母表,可以用手指上下滑动快速选择字母分组。
3. 再做一个当前选中的那个字母的显示。
先说第一件事。我们已经了解ListView/ListAdapter组合做出一个列表界面。那么,怎么在列表中显示一些不可选且模样不同的行,在SDK提供的例子其实是有相关代码可供参考的。
相关的代码是在ListAdapter中这两个方法:
[java]
view plain
copy
print?
@Override
public boolean areAllItemsEnabled() {
return false; //不是所有项都可选
}
@Override
public boolean isEnabled(int position) {
return !getItem(position).name.startsWith("@section"); //如果名字以@section开头,则该项不可选
}
简言之,在position这个项是否可选完全可以由你来控制的。
模样的问题也容易解决,只是这样做的效率会降低:
[java]
view plain
copy
print?
public View getView(int position, View convertView, ViewGroup parent) {
// 如果每一项都一样,就可以这样。
// if(convertView==null){
// convertView=mInflater.inflate(R.layout.friends_list_row, null);
// }
//但我们每一项的模样都可能不一样,只能这样了
FriendInfo item = (FriendInfo)getItem(position);
if(item!=null){
if(!item.name.startsWith("@section")){
convertView=mInflater.inflate(R.layout.friends_list_row, null);
//... ...
convertView.setTag(item);
}
else {
convertView=mInflater.inflate(R.layout.friends_list_section, null);
// ... ...
}
}
return convertView;
}
可以运行看看,第一个问题解决了。
第二个问题的处理就是找一张图,放在ListView的右边即可。先看看我们的Layout文件片断:
注意这个QuickAlphabeticBar是我们自定义的一个View,extends ImageButton,所以你可以先试试用ImageButton放这儿也能很快看到效果。
[xhtml]
view plain
copy
print?
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="0.0dip"
android:layout_weight="1.0">
<ListView
android:id="@id/friends_list"
android:scrollbars="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginLeft="0.0dip"
android:drawSelectorOnTop="false"
android:scrollingCache="true"
android:layout_weight="1.0"
android:fastScrollEnabled="false"
android:footerDividersEnabled="true"
android:cacheColorHint="#00000000"
style="@style/Widget.ListViewGreen"
/>
<cn.sharetop.xmessenger.ui.QuickAlphabeticBar
android:layout_gravity="top|right|center"
android:id="@id/fast_scroller"
android:background="@null"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10.0px"
android:scaleType="centerInside"
android:src="@drawable/contact_list_scroll_long" />
<TextView
android:id="@id/fast_position"
android:textSize="48dip"
android:textColor="#99FFFFFF"
android:background="@drawable/fast_scroller_overlay"
android:layout_gravity="center_horizontal|top"
android:padding="2dip"
android:layout_margin="24dip"
android:layout_width="@dimen/header_width"
android:layout_height="@dimen/header_width"
android:gravity="center"/>
</FrameLayout>
很好,这个字母表有了,因为我们需要对手指在上面滑动时的事件进行处理,所以我们自定义它,无非就是要处理这个onTouchEvent(MotionEvent event) 事件罢了,怎么处理?大家应该都想到了,就是根据手指所在位置算一下是哪个字母。
所以呢,我们先处理一下那个ListAdapter,让它implements SectionIndexer。
[java]
view plain
copy
print?
public class FriendsListAdapter extends ArrayAdapter<FriendInfo> implements SectionIndexer{
private Context mContext;
private LayoutInflater mInflater;
private HashMap<String, Integer> alphaIndexer;
private String[] sections = new String[0];
public FriendsListAdapter(Context context, int textViewResourceId,
List<BuddyInfo> objects) {
super(context, textViewResourceId, objects);
mContext=context;
mInflater=LayoutInflater.from(mContext);
initSections(objects);
}
//......
@Override
public int getPositionForSection(int section) {
String letter = sections[section];
return alphaIndexer.get(letter);
}
@Override
public int getSectionForPosition(int position) {
int prevIndex = 0;
for(int i = 0; i < sections.length; i++) {
if(getPositionForSection(i) > position && prevIndex <= position) {
prevIndex = i;
break;
}
prevIndex = i;
}
return prevIndex; }
@Override
public Object[] getSections() {
return sections;
}
private void initSections(List<BuddyInfo> items){
alphaIndexer = new HashMap<String, Integer>();
for(int i = items.size() - 1; i >= 0; i--) {
BuddyInfo element = items.get(i);
String firstChar = element.sortKey;//.substring(0, 1).toUpperCase();
if(firstChar.charAt(0) > 'Z' || firstChar.charAt(0) < 'A')
firstChar = "#";
alphaIndexer.put(firstChar, i);
}
Set<String> keys = alphaIndexer.keySet();
Iterator<String> it = keys.iterator();
ArrayList<String> keyList = new ArrayList<String>();
while(it.hasNext())
keyList.add(it.next());
Collections.sort(keyList);
sections = new String[keyList.size()];
keyList.toArray(sections);
}
}
然后,在QuickAlphabeticBar里的onTouchEvent里,我们可以快速定位到相应的段上:
[java]
view plain
copy
print?
@Override
public boolean onTouchEvent(MotionEvent event) {
int act=event.getAction();
//......
float y = event.getY();
//算手指位置,找到对应的段,让mList移动段开头的位置上
if(mListAdapter!=null){
int x=getAlphabeticPostion(y);
if(x<0)x=0;
if(x>=mSections.length) x=mSections.length-1;
int pos=((SectionIndexer)mListAdapter).getPositionForSection(x);
this.mList.setSelectionFromTop(pos, 0);
}
else{
this.mList.setSelectionFromTop(getAlphabeticPostion(y),0);
}
return super.onTouchEvent(event);
}
OK了,现在我们已经解决两个问题了,但是如何显示一个小的浮动窗口提示当前选中的段的首字母呢,也不复杂,大家注意到文章开头那个Layout中的ID为fast_position的TextView了吧?就是它了。
[java]
view plain
copy
print?
public class QuickAlphabeticBar extends ImageButton implements OnScrollListener {
//... ...
public void init(Context ctx){
mDialogText=(TextView)((FriendsActivity)ctx).findViewById(R.id.fast_position);
mDialogText.setVisibility(View.INVISIBLE);
mReady = true;
//... ...
}
//... ...
@Override
public void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {
if (mReady) {
if(mListAdapter!=null && mListAdapter.getCount()>0){
BuddyInfo item = (BuddyInfo)mListAdapter.getItem(firstVisibleItem);
char firstLetter = (item.sortKey!=null && item.sortKey.trim().length()>0)?item.sortKey.toUpperCase().charAt(0):' ';
if (!mShowing && firstLetter != mPrevLetter) {
mShowing = true;
mDialogText.setVisibility(View.VISIBLE);
}
mDialogText.setText(((Character)firstLetter).toString());
mHandler.removeCallbacks(mRemoveWindow);
mHandler.postDelayed(mRemoveWindow, 1000);
mPrevLetter = firstLetter;
}
}
}
//... ...
}
这段代码就是ListView滚动时,让mDialogText显示出来,并且设置它的内容为首字母即可。关键是那个mHandler,即1秒后要记得让它隐藏起来。
就是这么多事情了,大家可以试试。
http://blog.csdn.net/sharetop/article/details/6246629
其实可以这样归纳一下我们要做的事情:
1. 按首字母分组,显示一个分组的标签头。
2. 在右边做一个全字母表,可以用手指上下滑动快速选择字母分组。
3. 再做一个当前选中的那个字母的显示。
先说第一件事。我们已经了解ListView/ListAdapter组合做出一个列表界面。那么,怎么在列表中显示一些不可选且模样不同的行,在SDK提供的例子其实是有相关代码可供参考的。
相关的代码是在ListAdapter中这两个方法:
[java]
view plain
copy
print?
@Override
public boolean areAllItemsEnabled() {
return false; //不是所有项都可选
}
@Override
public boolean isEnabled(int position) {
return !getItem(position).name.startsWith("@section"); //如果名字以@section开头,则该项不可选
}
@Override public boolean areAllItemsEnabled() { return false; //不是所有项都可选 } @Override public boolean isEnabled(int position) { return !getItem(position).name.startsWith("@section"); //如果名字以@section开头,则该项不可选 }
简言之,在position这个项是否可选完全可以由你来控制的。
模样的问题也容易解决,只是这样做的效率会降低:
[java]
view plain
copy
print?
public View getView(int position, View convertView, ViewGroup parent) {
// 如果每一项都一样,就可以这样。
// if(convertView==null){
// convertView=mInflater.inflate(R.layout.friends_list_row, null);
// }
//但我们每一项的模样都可能不一样,只能这样了
FriendInfo item = (FriendInfo)getItem(position);
if(item!=null){
if(!item.name.startsWith("@section")){
convertView=mInflater.inflate(R.layout.friends_list_row, null);
//... ...
convertView.setTag(item);
}
else {
convertView=mInflater.inflate(R.layout.friends_list_section, null);
// ... ...
}
}
return convertView;
}
public View getView(int position, View convertView, ViewGroup parent) { // 如果每一项都一样,就可以这样。 // if(convertView==null){ // convertView=mInflater.inflate(R.layout.friends_list_row, null); // } //但我们每一项的模样都可能不一样,只能这样了 FriendInfo item = (FriendInfo)getItem(position); if(item!=null){ if(!item.name.startsWith("@section")){ convertView=mInflater.inflate(R.layout.friends_list_row, null); //... ... convertView.setTag(item); } else { convertView=mInflater.inflate(R.layout.friends_list_section, null); // ... ... } } return convertView; }
可以运行看看,第一个问题解决了。
第二个问题的处理就是找一张图,放在ListView的右边即可。先看看我们的Layout文件片断:
注意这个QuickAlphabeticBar是我们自定义的一个View,extends ImageButton,所以你可以先试试用ImageButton放这儿也能很快看到效果。
[xhtml]
view plain
copy
print?
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="0.0dip"
android:layout_weight="1.0">
<ListView
android:id="@id/friends_list"
android:scrollbars="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginLeft="0.0dip"
android:drawSelectorOnTop="false"
android:scrollingCache="true"
android:layout_weight="1.0"
android:fastScrollEnabled="false"
android:footerDividersEnabled="true"
android:cacheColorHint="#00000000"
style="@style/Widget.ListViewGreen"
/>
<cn.sharetop.xmessenger.ui.QuickAlphabeticBar
android:layout_gravity="top|right|center"
android:id="@id/fast_scroller"
android:background="@null"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10.0px"
android:scaleType="centerInside"
android:src="@drawable/contact_list_scroll_long" />
<TextView
android:id="@id/fast_position"
android:textSize="48dip"
android:textColor="#99FFFFFF"
android:background="@drawable/fast_scroller_overlay"
android:layout_gravity="center_horizontal|top"
android:padding="2dip"
android:layout_margin="24dip"
android:layout_width="@dimen/header_width"
android:layout_height="@dimen/header_width"
android:gravity="center"/>
</FrameLayout>
<FrameLayout android:layout_width="fill_parent" android:layout_height="0.0dip" android:layout_weight="1.0"> <ListView android:id="@id/friends_list" android:scrollbars="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_marginLeft="0.0dip" android:drawSelectorOnTop="false" android:scrollingCache="true" android:layout_weight="1.0" android:fastScrollEnabled="false" android:footerDividersEnabled="true" android:cacheColorHint="#00000000" style="@style/Widget.ListViewGreen" /> <cn.sharetop.xmessenger.ui.QuickAlphabeticBar android:layout_gravity="top|right|center" android:id="@id/fast_scroller" android:background="@null" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10.0px" android:scaleType="centerInside" android:src="@drawable/contact_list_scroll_long" /> <TextView android:id="@id/fast_position" android:textSize="48dip" android:textColor="#99FFFFFF" android:background="@drawable/fast_scroller_overlay" android:layout_gravity="center_horizontal|top" android:padding="2dip" android:layout_margin="24dip" android:layout_width="@dimen/header_width" android:layout_height="@dimen/header_width" android:gravity="center"/> </FrameLayout>
很好,这个字母表有了,因为我们需要对手指在上面滑动时的事件进行处理,所以我们自定义它,无非就是要处理这个onTouchEvent(MotionEvent event) 事件罢了,怎么处理?大家应该都想到了,就是根据手指所在位置算一下是哪个字母。
所以呢,我们先处理一下那个ListAdapter,让它implements SectionIndexer。
[java]
view plain
copy
print?
public class FriendsListAdapter extends ArrayAdapter<FriendInfo> implements SectionIndexer{
private Context mContext;
private LayoutInflater mInflater;
private HashMap<String, Integer> alphaIndexer;
private String[] sections = new String[0];
public FriendsListAdapter(Context context, int textViewResourceId,
List<BuddyInfo> objects) {
super(context, textViewResourceId, objects);
mContext=context;
mInflater=LayoutInflater.from(mContext);
initSections(objects);
}
//......
@Override
public int getPositionForSection(int section) {
String letter = sections[section];
return alphaIndexer.get(letter);
}
@Override
public int getSectionForPosition(int position) {
int prevIndex = 0;
for(int i = 0; i < sections.length; i++) {
if(getPositionForSection(i) > position && prevIndex <= position) {
prevIndex = i;
break;
}
prevIndex = i;
}
return prevIndex; }
@Override
public Object[] getSections() {
return sections;
}
private void initSections(List<BuddyInfo> items){
alphaIndexer = new HashMap<String, Integer>();
for(int i = items.size() - 1; i >= 0; i--) {
BuddyInfo element = items.get(i);
String firstChar = element.sortKey;//.substring(0, 1).toUpperCase();
if(firstChar.charAt(0) > 'Z' || firstChar.charAt(0) < 'A')
firstChar = "#";
alphaIndexer.put(firstChar, i);
}
Set<String> keys = alphaIndexer.keySet();
Iterator<String> it = keys.iterator();
ArrayList<String> keyList = new ArrayList<String>();
while(it.hasNext())
keyList.add(it.next());
Collections.sort(keyList);
sections = new String[keyList.size()];
keyList.toArray(sections);
}
}
public class FriendsListAdapter extends ArrayAdapter<FriendInfo> implements SectionIndexer{ private Context mContext; private LayoutInflater mInflater; private HashMap<String, Integer> alphaIndexer; private String[] sections = new String[0]; public FriendsListAdapter(Context context, int textViewResourceId, List<BuddyInfo> objects) { super(context, textViewResourceId, objects); mContext=context; mInflater=LayoutInflater.from(mContext); initSections(objects); } //...... @Override public int getPositionForSection(int section) { String letter = sections[section]; return alphaIndexer.get(letter); } @Override public int getSectionForPosition(int position) { int prevIndex = 0; for(int i = 0; i < sections.length; i++) { if(getPositionForSection(i) > position && prevIndex <= position) { prevIndex = i; break; } prevIndex = i; } return prevIndex; } @Override public Object[] getSections() { return sections; } private void initSections(List<BuddyInfo> items){ alphaIndexer = new HashMap<String, Integer>(); for(int i = items.size() - 1; i >= 0; i--) { BuddyInfo element = items.get(i); String firstChar = element.sortKey;//.substring(0, 1).toUpperCase(); if(firstChar.charAt(0) > 'Z' || firstChar.charAt(0) < 'A') firstChar = "#"; alphaIndexer.put(firstChar, i); } Set<String> keys = alphaIndexer.keySet(); Iterator<String> it = keys.iterator(); ArrayList<String> keyList = new ArrayList<String>(); while(it.hasNext()) keyList.add(it.next()); Collections.sort(keyList); sections = new String[keyList.size()]; keyList.toArray(sections); } }
然后,在QuickAlphabeticBar里的onTouchEvent里,我们可以快速定位到相应的段上:
[java]
view plain
copy
print?
@Override
public boolean onTouchEvent(MotionEvent event) {
int act=event.getAction();
//......
float y = event.getY();
//算手指位置,找到对应的段,让mList移动段开头的位置上
if(mListAdapter!=null){
int x=getAlphabeticPostion(y);
if(x<0)x=0;
if(x>=mSections.length) x=mSections.length-1;
int pos=((SectionIndexer)mListAdapter).getPositionForSection(x);
this.mList.setSelectionFromTop(pos, 0);
}
else{
this.mList.setSelectionFromTop(getAlphabeticPostion(y),0);
}
return super.onTouchEvent(event);
}
@Override public boolean onTouchEvent(MotionEvent event) { int act=event.getAction(); //...... float y = event.getY(); //算手指位置,找到对应的段,让mList移动段开头的位置上 if(mListAdapter!=null){ int x=getAlphabeticPostion(y); if(x<0)x=0; if(x>=mSections.length) x=mSections.length-1; int pos=((SectionIndexer)mListAdapter).getPositionForSection(x); this.mList.setSelectionFromTop(pos, 0); } else{ this.mList.setSelectionFromTop(getAlphabeticPostion(y),0); } return super.onTouchEvent(event); }
OK了,现在我们已经解决两个问题了,但是如何显示一个小的浮动窗口提示当前选中的段的首字母呢,也不复杂,大家注意到文章开头那个Layout中的ID为fast_position的TextView了吧?就是它了。
[java]
view plain
copy
print?
public class QuickAlphabeticBar extends ImageButton implements OnScrollListener {
//... ...
public void init(Context ctx){
mDialogText=(TextView)((FriendsActivity)ctx).findViewById(R.id.fast_position);
mDialogText.setVisibility(View.INVISIBLE);
mReady = true;
//... ...
}
//... ...
@Override
public void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {
if (mReady) {
if(mListAdapter!=null && mListAdapter.getCount()>0){
BuddyInfo item = (BuddyInfo)mListAdapter.getItem(firstVisibleItem);
char firstLetter = (item.sortKey!=null && item.sortKey.trim().length()>0)?item.sortKey.toUpperCase().charAt(0):' ';
if (!mShowing && firstLetter != mPrevLetter) {
mShowing = true;
mDialogText.setVisibility(View.VISIBLE);
}
mDialogText.setText(((Character)firstLetter).toString());
mHandler.removeCallbacks(mRemoveWindow);
mHandler.postDelayed(mRemoveWindow, 1000);
mPrevLetter = firstLetter;
}
}
}
//... ...
}
public class QuickAlphabeticBar extends ImageButton implements OnScrollListener { //... ... public void init(Context ctx){ mDialogText=(TextView)((FriendsActivity)ctx).findViewById(R.id.fast_position); mDialogText.setVisibility(View.INVISIBLE); mReady = true; //... ... } //... ... @Override public void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) { if (mReady) { if(mListAdapter!=null && mListAdapter.getCount()>0){ BuddyInfo item = (BuddyInfo)mListAdapter.getItem(firstVisibleItem); char firstLetter = (item.sortKey!=null && item.sortKey.trim().length()>0)?item.sortKey.toUpperCase().charAt(0):' '; if (!mShowing && firstLetter != mPrevLetter) { mShowing = true; mDialogText.setVisibility(View.VISIBLE); } mDialogText.setText(((Character)firstLetter).toString()); mHandler.removeCallbacks(mRemoveWindow); mHandler.postDelayed(mRemoveWindow, 1000); mPrevLetter = firstLetter; } } } //... ... }
这段代码就是ListView滚动时,让mDialogText显示出来,并且设置它的内容为首字母即可。关键是那个mHandler,即1秒后要记得让它隐藏起来。
就是这么多事情了,大家可以试试。
http://blog.csdn.net/sharetop/article/details/6246629
相关文章推荐
- 创新源于模仿之二:美化ListView的尝试
- 创新源于模仿之二:美化ListView的尝试
- 创新源于模仿之二:美化ListView的尝试
- 创新源于模仿之二:美化ListView的尝试
- 创新源于模仿之一:TabActivity的美化
- 创新源于模仿之一:TabActivity的美化
- 创新源于模仿之一:TabActivity的美化
- 创新源于模仿之四:增强的ExpandableListView
- 创新源于模仿之五:做一个自己的QuickAction
- 创新源于模仿之六:仿iPhone的分组列表做一个配置界面
- 创新源于模仿之四:增强的ExpandableListView
- 创新源于模仿之三:实现左右两个屏幕的切换
- 美化ListView的尝试
- 创新源于模仿之四:增强的ExpandableListView
- 美化ListView的尝试
- 创新源于模仿之一:TabActivity的美化
- 创新源于模仿之五:做一个自己的QuickAction
- 创新源于模仿之三:实现左右两个屏幕的切换
- 创新源于模仿之六:仿iPhone的分组列表做一个配置界面
- 创新源于模仿之四:增强的ExpandableListView