Android TV ListView通过遥控器上下键,平滑移动item

项目中有这样一个需求,ListView列表里面的Item选中项(即焦点所在item),需要始终保持在LsitView的中间位置,即不管是按遥控器下键还是上键,焦点所在的item必须能移回到整个listView的居中位置。

如图中所示:



默认情况下,当我们按下键选择item的时候,焦点会一直往下走,当选择到当前ListView中可视的最后一个item的时候,焦点就会固定在最后一个item上,比如这时候选择了item5,那么我们在按下键选择item6的时候,焦点依旧在item5的位置,但是内容已经被item6填充了,item5则上移了一个位置。


根据我们的需求,比如我的选中焦点始终默认在item3的位置(即ListView的中间位置),也就是说当我下键选择item4的时候,焦点肯定下移了一个item的位置,这时候我就需要再把这个item4上移一个位置,即回到item3的位置。那么此时就用到了ListView的scroll方法,使用这些方法就相当于用手势控制了滚动条的位置,根据滚动的距离,我们就可以把整个listview的数据上移或下移的。

目前我这里使用到的方法是:

smoothScrollToPositionFromTop( int position,  int offset,  int duration)
postion参数表示要选中的item在adapter中的位置;
offset表示我当前选中的pisition上的item距离Listview的顶部的位置,比如我这里把这个距离设置成listview的高度的一半,那么就可以让我选中的item始终跟ListView的顶部有一半的距离。这样就实现了居中;
duration表示平滑移动的时间,时间越久移动得越缓慢,看起来越平滑。
还有一种情况下,向下按键的时候,需要选中的item(即焦点)始终保持在ListView的可见item的第一个,向上按键的时候,需要选中的item(即焦点)始终保持在ListView可见item的最后一个上。那么这里就用上了另外一个方法:

smoothScrollBy( int distance, int duration)
distance参数表示移动的距离,
duration表示移动的时间
实际使用时,我们按下键的时候,只需要向上移动一个item距离,按上键的时候,值需要向下移动一个item的距离,就能实现效果了。

胡打乱撞的找了些资料看看,基本上解决了需求,但是具体这两个方法和其他相类似的方法有些什么区别和作用还需要进一步的认识。

记录已下,以后理解了好补充。


非常感谢这篇文章:android ListView TV 通过遥控器上下 smooth滑动

让我理解了不少,唯一的缺憾是不知道作者是谁,没法深入请教啊~


顺便贴已下完整的源码:

package com.golive.view;

import java.util.Timer;
import java.util.TimerTask;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnKeyListener;
import android.widget.ListAdapter;
import android.widget.ListView;

public class SmoothScrollListView extends ListView implements OnKeyListener {

	private String TAG = SmoothScrollListView.class.getSimpleName();
	private int itemsCount;

	private int itemHeight;

	private ListAdapter adapter;

	private int scrollDuration = 100;

	private boolean isScrollTop;

	private Timer timer;

	private OnScrollBottomListener onScrollBottomListener;

	private OnScrollTopListener onScrollTopListener;

	public SmoothScrollListView(Context context) {
		this(context, null);
	}

	public SmoothScrollListView(Context context, AttributeSet attrs) {
		super(context, attrs);
		this.setOnKeyListener(this);
		this.setSmoothScrollbarEnabled(true);

	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		super.onLayout(changed, l, t, r, b);
		if (adapter != null) {
			// 获取每个item 的高度,因为要调用滑动的方法,每次滑动的距离就是item 的高度
			itemHeight = this.getChildAt(0).getHeight();
		}

	}

	@Override
	public void setAdapter(ListAdapter adapter) {
		super.setAdapter(adapter);
		this.adapter = adapter;
		// 获取listview
		// item的count,一定要是由adapter获得,不能通过listView,因为listView是动态添加删除孩子的,可以打印一下比较看看
		itemsCount = adapter.getCount();

	}

	/**
	 * 设置滚动动画的滚动时间
	 * 
	 * @param scrollDutation
	 */
	public void setScrollDuration(int scrollDutation) {
		this.scrollDuration = scrollDutation;

	}

	@Override
	public boolean onKey(View v, int keyCode, KeyEvent event) {
		if (event.getAction() == KeyEvent.ACTION_UP) {
			return false;
		}
		// 获取当前被选中的位置
		int currentItemPosition = this.getSelectedItemPosition();
//		this.setSelectionFromTop(currentItemPosition, this.getHeight()/2);
		if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {

			// 当是倒数第二个的时候
			if (currentItemPosition == itemsCount - 2) {
				// 如果listView的最后一个可见Item是倒数第二个item,或者是倒数第一个item同时timer不为空,这时要滚动一次,并让最后一个item获取焦点
				if (this.getLastVisiblePosition() == itemsCount - 2
						|| (this.getLastVisiblePosition() == itemsCount - 1 && timer != null)) {
					Log.e(TAG,"倒数第二个");
					this.smoothScrollBy(itemHeight, scrollDuration);

					if (timer == null) {
						smoothScrollToBottom();
					} else {
						timer.cancel();
						timer = null;
						// 延迟一下,再让最后一个item编程selected状态,不让没有动画,太突兀
						smoothScrollToBottom();
					}

					// this.smoothScrollToPositionFromTop(itemsCount - 1, 0,
					// scrollDuration);
					// this.setSelection(itemsCount - 1);
				}
				return false;
			} else if (currentItemPosition == itemsCount - 1) {
				setSelection(0);//这里设置循环选择,最后一个item的时候,按键向下,默认设置选中第一个item
				// 当是最后一个item是selectionItem,则给出回调,让他不要在滚动了
				if (onScrollBottomListener != null) {
					onScrollBottomListener.onScrollBottom();
				}
				return true;
			} else {
				// 是中间其他状态的时候,滚动一个item的距离,不保证选中的item具体在ListView的什么位置。
				//比如,当前选中的item0在ListView的最顶端,则选择下一个item1时,这个item1会移动到之前选中的item0的位置
				//this.smoothScrollBy(itemHeight, scrollDuration);
				 this.smoothScrollToPositionFromTop(currentItemPosition + 1,
				 this.getHeight()/2, scrollDuration);//始终保持当前选择的item在ListView的最中间
				return false;
			}
		}

		if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
			if (currentItemPosition == 1) {

				if (this.getChildAt(0).isFocusable() == false) {
					this.smoothScrollBy(-itemHeight, scrollDuration);
				}
				return false;
			} else if (currentItemPosition == 0) {
				setSelection(itemsCount-1);//第一个item的时候,按键向上默认选中最后一个item
				if (onScrollTopListener != null) {
					onScrollTopListener.onScrollTop();
				}

				return isScrollTop;
			} else {
				//两种选择,原理和按下键一样
//				this.smoothScrollBy(-itemHeight, scrollDuration);
				this.smoothScrollToPositionFromTop(currentItemPosition - 1,
						 this.getHeight()/2, scrollDuration);
				return false;
			}
		}

		return false;
	}

	private void smoothScrollToBottom() {
		Log.e(TAG,"平滑移动到最后");
		timer = new Timer();
		timer.schedule(new TimerTask() {

			@Override
			public void run() {
				SmoothScrollListView.this.post(new Runnable() {

					@Override
					public void run() {
						SmoothScrollListView.this
								.setSelection(SmoothScrollListView.this
										.getLastVisiblePosition());

					}
				});

			}
		}, scrollDuration / 3);
	}

	/**
	 * 当滚动到底部的时候的监听
	 */
	public interface OnScrollBottomListener {
		void onScrollBottom();
	}

	public void setOnScrollBottomListener(
			OnScrollBottomListener onScrollBottomListener) {

		this.onScrollBottomListener = onScrollBottomListener;
	}

	/**
	 * 当滚动到顶部的时候的监听
	 */
	public interface OnScrollTopListener {
		void onScrollTop();
	}

	public void setOnScrollTopListener(OnScrollTopListener onScrollTopListener) {
		isScrollTop = true;
		this.onScrollTopListener = onScrollTopListener;
	}

}




  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
### 回答1: 在 AndroidListView 中删除项目的方法: 1. 在数据源中删除该项(例如 ArrayList)。 2. 调用 adapter 的 notifyDataSetChanged() 方法,以更新 ListView。 代码示例: ``` // 删除数据源中的项 list.remove(position); // 更新 ListView adapter.notifyDataSetChanged(); ``` ### 回答2: 在Android开发中,ListView是一个非常常用的控件。在使用ListView时,经常需要对其进行操作,比如删除item。那么该如何实现ListViewitem删除呢?接下来就来介绍一下ListViewitem删除实现方法。 1. ListView删除item的基本方法 ListView删除item的基本方法是通过Adapter来实现的,具体步骤如下: 1) 获取Adapter对象。 2) 调用Adapter对象的remove()方法或者使用List集合的remove()方法删除指定的item。 3) 调用Adapter对象的notifyDataSetChanged()方法更新ListView。 下面是代码实现: ``` adapter.remove(position); // 其中adapter为ListView的适配器对象,position为需要删除的item的位置 adapter.notifyDataSetChanged(); ``` 2. ListView删除item的动画效果 在对ListViewitem进行删除操作时,为了提升用户体验,可以使用动画效果。ListView删除item的动画效果需要在删除item后再进行动画展示,具体实现如下: ``` adapter.remove(position); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { lv.animate().alpha(0).setDuration(500).setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { adapter.notifyDataSetChanged(); lv.setAlpha(1); } }); } else { adapter.notifyDataSetChanged(); } ``` 其中,lv为ListView对象,上述代码中使用了渐隐动画效果,动画时间为500毫秒。 以上就是ListView删除item的实现方法,需要注意的是,在对ListViewitem进行修改时,需要更新ListView,否则不会生效。另外,如果需要使用动画效果,应该在删除之后再进行动画展示。 ### 回答3: 在Android中,ListView是一种常用的控件,它可以展示一组数据,并且允许用户进行交互,包括增加、删除或者编辑其中的一项数据。在ListView中删除一项数据,通常需要以下几个步骤: 1. 定义ListView和适配器 首先,需要在XML文件中定义ListView控件,并为其指定一个适配器,适配器是用来将数据绑定到ListView上的。 2. 实现删除功能 当用户选择要删除的项时,应该实现相应的删除功能。在数据层面上,需要更新数据源中的数据,以便在ListView上反映这些变化。在适配器中,调用notifyDataSetChanged()方法,以便使ListView重新加载数据。 3. 显示删除确认对话框 在进行删除操作之前,最好要显示一个确认对话框,以避免用户误删数据。在对话框中,通常会显示删除的项的详细信息,并要求用户确认。 4. 处理删除操作 当用户进行了确认后,便可以执行删除操作。在数据源中删除相应的数据,并调用适配器的notifyDataSetChanged()方法,MasterNode就可以刷新视图并显示最新的数据了。 总结 在Android中,ListView的删除功能实现并不复杂,但是需要仔细考虑删除的逻辑,以避免误删数据或引起其他错误。通过实现删除功能,用户可以更加方便地操作ListView,提高了应用程序的交互性和易用性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值