android ListView-选中项固定在某一项

来源:互联网 发布:多个excel表格数据汇总 编辑:程序博客网 时间:2024/05/18 00:22

最近做盒子项目,需要做一个列表效果,用遥控器上下移动列表时,选中项始终在第三行,且移动时有动画。起初想到使用自定义View来实现,这样确实很方便,但是有一个问题,当我需要更新列表时需要每次重新删除所有的View,再重新创建,而且当列表项很多时,需要创建很多的View,而且动画还需要自己重写。然后就想到是否可以在ListView的基础上实现的这样的效果,因为即使列表项很多时,ListView的创建的View个数也很少,而且它的Adapter刷新机制很方便,而且可以直接使用它的动画。


效果图如下:



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() {@Overridepublic 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() {@Overridepublic 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);}}@Overridepublic 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中将焦点框画出来@Overrideprotected 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);}//自定义的ListViewprivate 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);}//此处用来防止快速移动时,造成选中项和焦点框对不齐的问题,这样做引起了一个问题,快速移动时有点慢@Overridepublic 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。

@Overrideprotected 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的特性,特别是一些特殊的需求,如需添加头和尾。


代码下载链接:点击打开链接

0 0
原创粉丝点击