android ListView-选中项固定在某一项
2014-10-31 16:34
190 查看
最近做盒子项目,需要做一个列表效果,用遥控器上下移动列表时,选中项始终在第三行,且移动时有动画。起初想到使用自定义View来实现,这样确实很方便,但是有一个问题,当我需要更新列表时需要每次重新删除所有的View,再重新创建,而且当列表项很多时,需要创建很多的View,而且动画还需要自己重写。然后就想到是否可以在ListView的基础上实现的这样的效果,因为即使列表项很多时,ListView的创建的View个数也很少,而且它的Adapter刷新机制很方便,而且可以直接使用它的动画。
效果图如下:
1.创建BaseListView,此实际上是一个RelativeLayout,在其中添加一个ListView,封装了很多ListView的方法,但是ListView不对外开放。
(1).固定Item在第三项,使用ListView的smoothScrollBy方法来控制。其中的难点是每次选中项后要计算移动的偏差值。
(2).当移动到列表的最上面或者最下面时,smoothScrollBy方法失效,选中项不会固定在第三项的位置,会直接移到上面去或者下面。解决的方法是在列表上方添加List几个头部和list几个尾部,但是头部和尾部都不能选中。
直接贴出BaseListView的代码:
2.创建ListView的Adapter(BaseItemAdapter),使用ViewHolder机制来优化,此处就不做详细介绍了。
3.使用
(1)代码结构
(2)在xml使用BaseListView
(3)继承BaseItemData(TestItemData)和BaseItemView(TestItemView),然后在activity中创建BaseItemAdapter。
4.不足之处:
(1)遥控器快速向下滑动时,移动很慢。
(2)ListView不开放,无法使用一些ListView的特性,特别是一些特殊的需求,如需添加头和尾。
代码下载链接:点击打开链接
效果图如下:
1.创建BaseListView,此实际上是一个RelativeLayout,在其中添加一个ListView,封装了很多ListView的方法,但是ListView不对外开放。
(1).固定Item在第三项,使用ListView的smoothScrollBy方法来控制。其中的难点是每次选中项后要计算移动的偏差值。
(2).当移动到列表的最上面或者最下面时,smoothScrollBy方法失效,选中项不会固定在第三项的位置,会直接移到上面去或者下面。解决的方法是在列表上方添加List几个头部和list几个尾部,但是头部和尾部都不能选中。
直接贴出BaseListView的代码:
package com.hm.test.view.base; import com.hm.test.R; import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.widget.AbsListView; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.HeaderViewListAdapter; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.RelativeLayout; public class BaseListView extends RelativeLayout { //选中项和非选中项的高度不一样。 private int mFocusedWidth = 400; private int mFocusedHeight = 140; private int mNormalWidth = 400; private int mNormalHeight = 80; //固定显示十项 private int mShowItemCount = 10; //默认选中项始终在第三项 private int mBaseIndex = 2; //ListView,不对外开放 private ListView mListView; private Drawable mBaseItemMask; private Drawable mBaseitemBorder; private OnItemClickListener mItemClickListener; private OnItemSelectedListener mItemSelectedListener; public BaseListView(Context context) { this(context, null); } public BaseListView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public BaseListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); setWillNotDraw(false); final Resources res = getResources(); mFocusedWidth = res.getDimensionPixelSize(R.dimen.baselist_item_focused_width); mFocusedHeight = res.getDimensionPixelSize(R.dimen.baselist_item_focused_height); mNormalWidth = res.getDimensionPixelSize(R.dimen.baselist_item_normal_width); mNormalHeight = res.getDimensionPixelSize(R.dimen.baselist_item_normal_height); mBaseItemMask = res.getDrawable(R.drawable.base_item_bottom_mask); mBaseitemBorder = res.getDrawable(R.drawable.base_item_border); RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(mNormalWidth, mNormalHeight * (mShowItemCount - 1) + mFocusedHeight); lp.addRule(RelativeLayout.CENTER_IN_PARENT); mListView = new MyListView(context, attrs, defStyle); mListView.setSelector(R.drawable.base_item_view_bg); mListView.setDivider(null); mListView.setCacheColorHint(Color.TRANSPARENT); mListView.setOnItemClickListener(mBaseItemClickListener); mListView.setOnItemSelectedListener(mBaseItemSelectedListener); addView(mListView, lp); } private OnItemClickListener mBaseItemClickListener = new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { if (mItemClickListener != null) { mItemClickListener.onItemClick(parent, view, position - mListView.getHeaderViewsCount(), id); } } }; private OnItemSelectedListener mBaseItemSelectedListener = new OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { Log.e("//////", "onItemSelected " + position + " " + view.getTop() + " " + parent.getScrollY()); mListView.scrollTo(mListView.getScrollX(), 0); if (view != null) { //此处选中时调用ListView的移动动画,计算偏移值:通过选中View的top和第三项的高度来计算 mListView.smoothScrollBy(view.getTop() - mBaseIndex * mNormalHeight - mListView.getScrollY(), 250); } if (mItemSelectedListener != null) { mItemSelectedListener.onItemSelected(parent, view, position - mListView.getHeaderViewsCount(), id); } } @Override public void onNothingSelected(AdapterView<?> parent) { if (mItemSelectedListener != null) { mItemSelectedListener.onNothingSelected(parent); } } }; //封装ListView的setAdapter方法 public void setAdapter(BaseItemAdapter adapter) { mListView.setAdapter(adapter); } //封装ListView的getAdapter方法 public BaseItemAdapter getAdapter() { ListAdapter adapter = mListView.getAdapter(); if (adapter instanceof BaseItemAdapter) { return (BaseItemAdapter) adapter; } else if (adapter instanceof HeaderViewListAdapter) { HeaderViewListAdapter headerAdapter = (HeaderViewListAdapter) adapter; ListAdapter listAdapter = headerAdapter.getWrappedAdapter(); if (listAdapter instanceof BaseItemAdapter) { return (BaseItemAdapter) listAdapter; } } return null; } //封装ListView的setOnItemClickListener方法 public void setOnItemClickListener(OnItemClickListener l) { mItemClickListener = l; } //封装ListView的setOnItemSelectedListener方法 public void setOnItemSelectedListener(OnItemSelectedListener l) { mItemSelectedListener = l; } //封装ListView的setSelection方法 public void setSelection(int position) { BaseItemAdapter adapter = getAdapter(); int realPositon = 0; if (adapter != null) { int size = adapter.getCount(); if (position < 0) { realPositon = 0; } else if (position >= size) { realPositon = size - 1; } else { realPositon = position; } } mListView.setSelection(realPositon + mListView.getHeaderViewsCount()); } //在dispatchDraw中将焦点框画出来 @Override protected void dispatchDraw(Canvas canvas) { int width = getWidth(); int left = 0; int top = mListView.getTop() + mBaseIndex * mNormalHeight; int right = left + width; int bottom = top + mFocusedHeight; mBaseItemMask.setBounds(left, top, right, bottom); mBaseItemMask.draw(canvas); Rect padding = new Rect(); mBaseitemBorder.getPadding(padding); left = mListView.getLeft() - padding.left; right = left + mFocusedWidth + padding.left + padding.right; top = mListView.getTop() + mBaseIndex * mNormalHeight - padding.top; bottom = top + mFocusedHeight + padding.top + padding.bottom; mBaseitemBorder.setBounds(left, top, right, bottom); mBaseitemBorder.draw(canvas); super.dispatchDraw(canvas); } //自定义的ListView private class MyListView extends ListView { public MyListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); //关键点在这个地方:如果不加头和尾,当移动到上面或者下面时,不能固定到第三项 for (int i = 0; i < mBaseIndex; i++) { View headerView = new View(context); AbsListView.LayoutParams headerLp = new AbsListView.LayoutParams(mNormalWidth, mNormalHeight); headerView.setLayoutParams(headerLp); //添加时必须要传递参数false,使头和尾不能选中 addHeaderView(headerView, null, false); } for (int i = 0; i < mShowItemCount - mBaseIndex - 1; i++) { View footerView = new View(context); AbsListView.LayoutParams footerLp = new AbsListView.LayoutParams(mNormalWidth, mNormalHeight); footerView.setLayoutParams(footerLp); addFooterView(footerView, null, false); } setPadding(0, 0, 0, 0); } //此处用来防止快速移动时,造成选中项和焦点框对不齐的问题,这样做引起了一个问题,快速移动时有点慢 @Override public boolean dispatchKeyEvent(KeyEvent event) { int action = event.getAction(); int keyCode = event.getKeyCode(); View view = mListView.getSelectedView(); if (action == KeyEvent.ACTION_DOWN && view != null) { int top = view.getTop(); if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN || keyCode == KeyEvent.KEYCODE_DPAD_UP) { if ((mBaseIndex * mNormalHeight) != top) { return false; } } } return super.dispatchKeyEvent(event); } } }
2.创建ListView的Adapter(BaseItemAdapter),使用ViewHolder机制来优化,此处就不做详细介绍了。
3.使用
(1)代码结构
(2)在xml使用BaseListView
<?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:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/app_name" android:textColor="@android:color/white" android:textSize="40sp" /> <com.hm.test.view.base.BaseListView android:id="@+id/test_layout_baselist" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
(3)继承BaseItemData(TestItemData)和BaseItemView(TestItemView),然后在activity中创建BaseItemAdapter。
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test); mBaseListView = (BaseListView) findViewById(R.id.test_layout_baselist); BaseItemAdapter adapter = new BaseItemAdapter(this); for (int i = 0; i < 15; i++) { TestItemData data = new TestItemData(); data.index = i; adapter.add(data); } mBaseListView.setAdapter(adapter); }
4.不足之处:
(1)遥控器快速向下滑动时,移动很慢。
(2)ListView不开放,无法使用一些ListView的特性,特别是一些特殊的需求,如需添加头和尾。
代码下载链接:点击打开链接
相关文章推荐
- 【Android特效一】listview固定选中一项,整个列表上移下移。
- Android单选中listview中的一项
- Android ListView默认选中某一项
- Android ListView 默认选中某一项
- Android ListView 默认选中某一项实现代码
- android上改变listView的选中颜色 (转)
- android 中的ListView选中项的背景颜色怎么设置?
- Android中ListView结合CheckBox判断选中项
- Android中ListView结合CheckBox判断选中项
- 【android】listview改变选中行字体颜色
- Android ListView 去除底色、选中色、阴影
- Android ListView 去除边缘阴影、选中色、拖动背景色等
- 【android】listview改变选中行背景图片
- Android ListView选中变色
- Android中ListView结合CheckBox判断选中项
- Android改变ListView选中行字体颜色
- android上改变listView的选中颜色
- Android ListView 事件监听 || 关于ListView选中时显示的效果。
- 【Android】listview选中行字体变大
- [Android]ListView美化:去阴影、底色、选中色