好。 我试图做到的,是一个布局,做在Excel冻结窗格同样的效果。 这就是我想要一个标题行与主ListView和与主ListView控件垂直滚动左手的ListView水平滚动。 标题行和左手列表视图中的其他维度滚动时应该保持静止。
下面是XML布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/recordViewLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<LinearLayout android:layout_width="160dp"
android:layout_height="match_parent"
android:orientation="vertical">
<CheckBox
android:id="@+id/checkBoxTop"
android:text="Check All"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ListView android:id="@+id/engNameList"
android:layout_width="160dp"
android:layout_height="wrap_content"/>
</LinearLayout>
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout android:id="@+id/scroll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<include layout="@layout/record_view_line" android:id="@+id/titleLine" />
<ListView
android:id="@android:id/list"
android:layout_height="wrap_content"
android:layout_width="match_parent"/>
</LinearLayout>
</HorizontalScrollView>
</LinearLayout>
然后我使用这个代码在ListActivity
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
View v = recordsListView.getChildAt(0);
int top = (v == null) ? 0 : v.getTop();
((ListView)findViewById(R.id.engNameList)).setSelectionFromTop(firstVisibleItem, top);
}
这应当引起时,右手一个由用户滚动左手的ListView滚动。 不幸的是事实并非如此。
我已经有点关于谷歌和它似乎setSelectionFromTop()函数将无法在嵌套在一个以上的布局一个ListView工作。
如果是这样的话任何人都可以提出一个方法,让他们一起或以不同的方式来设置布局或不同的技术完全滚动。
Answer 1:
改写
我没有与通过滚动操作在一个ListView控件到另一个多少运气。 所以,我选择了不同的方法:传递MotionEvent
。 这让每一个ListView
计算自己的平滑滚动,快速滚动,或其他任何东西。
首先,我们需要一些类变量:
ListView listView;
ListView listView2;
View clickSource;
View touchSource;
int offset = 0;
我添加到每个方法listView
将是几乎相同listView2
,唯一的区别是, listView2
将引用listView
(未本身)。 我不包括重复listView2
代码。
其次,让我们先从OnTouchListener:
listView = (ListView) findViewById(R.id.engNameList);
listView.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if(touchSource == null)
touchSource = v;
if(v == touchSource) {
listView2.dispatchTouchEvent(event);
if(event.getAction() == MotionEvent.ACTION_UP) {
clickSource = v;
touchSource = null;
}
}
return false;
}
});
为了防止循环逻辑: listView
调用listView2
调用listView
调用...我用一个类变量touchSource
确定何时MotionEvent
应该传递。 我以为你不希望连续点击listView
也点击listView2
,所以我用另一个类变量clickSource
防止这种情况。
三,OnItemClickListener:
listView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if(parent == clickSource) {
// Do something with the ListView was clicked
}
}
});
四,通过每一个触摸事件,因为偶尔出现的差异是不完美的。 该OnScrollListener是完美的消除这些:
listView.setOnScrollListener(new OnScrollListener() {
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if(view == clickSource)
listView2.setSelectionFromTop(firstVisibleItem, view.getChildAt(0).getTop() + offset);
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {}
});
(可选)最后,你提到你有麻烦,因为listView
和listView2
开始在你的布局不同的高度......我强烈建议修改你的布局,以平衡列表视图,但我找到了一种方法来解决这个问题。 然而,它是有点棘手。
你不能计算出两种布局之间的高度差,直到整个布局已经呈现后,但没有回调这一刻......所以我用一个简单的处理程序:
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
// Set listView's x, y coordinates in loc[0], loc[1]
int[] loc = new int[2];
listView.getLocationInWindow(loc);
// Save listView's y and get listView2's coordinates
int firstY = loc[1];
listView2.getLocationInWindow(loc);
offset = firstY - loc[1];
//Log.v("Example", "offset: " + offset + " = " + firstY + " + " + loc[1]);
}
};
我认为半秒的延迟是足够长的时间来呈现布局和启动定时器onResume()
handler.sendEmptyMessageDelayed(0, 500);
如果你使用的偏移我要明确的是, listView2
的OnScroll方法减去偏移,而不是将其添加:
listView2.setSelectionFromTop(firstVisibleItem, view.getChildAt(0).getTop() - offset);
希望帮助!
Answer 2:
好。 我现在有一个答案。 问题是,如果列表视图在顶部布局.setSelectionFromTop()只会工作(即没有嵌套)。 Afters有些挠头,我意识到,我可以让我的布局的RelativeLayout,并得到相同的外观,但不必窝布局复选框和ListView。 这是新的布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/recordViewLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<CheckBox android:id="@+id/checkBoxTop"
android:text="Check All"
android:layout_width="160dp"
android:layout_height="wrap_content"/>"
<ListView android:id="@+id/engNameList"
android:layout_width="160dp"
android:layout_height="wrap_content"
android:layout_below="@+id/checkBoxTop"/>
<HorizontalScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/checkBoxTop">
<LinearLayout android:id="@+id/scroll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<include layout="@layout/record_view_line" android:id="@+id/titleLine" />
<ListView
android:id="@android:id/list"
android:layout_height="wrap_content"
android:layout_width="match_parent"/>
</LinearLayout>
</HorizontalScrollView>
</RelativeLayout>
这基本上是与布局而来的代码。
在的onCreate()
engListView=getListView();
engListView.setOnTouchListener(this);
recordListView=(ListView)findViewById(R.id.recordList);
recordListView.setOnScrollListener(this);
与听者的方法:
public boolean onTouch(View arg0, MotionEvent event) {
recordListView.dispatchTouchEvent(event);
return false;
}
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
View v=view.getChildAt(0);
if(v != null)
engListView.setSelectionFromTop(firstVisibleItem, v.getTop());
}
Answer 3:
此帖已帮我找到了一个类似的问题,我一直在挣扎了一段时间的解决方案。 也正是基于对拦截触摸事件。 在这种情况下,同步适用于多个列表视图,并且是完全对称的。
主要的挑战是防止列表条目点击传播到其他列表视图。 我需要点击,长点击只能由最初收到的触摸事件,其中包括特别的亮点反馈,当你刚刚接触下来的项目列表视图出动(拦截onClick事件是没有用的,因为它是为时已晚在调用层次)。
这里的关键是拦截触摸事件的两倍。 首先,初始触摸事件被转发到其他的列表视图。 同样onTouch处理函数捕获这些并把它们送至一个GestureDetector。 在GestureDetector
回调静电触摸事件( onDown
等)消耗( return true
),而运动姿态都没有( return false
),使得他们可以通过视图本身进一步出动,并触发滚动。
使用setPositionFromTop
内onScroll
,因为它使滚动行为极为低迷并没有为我工作。 OnScroll来代替对准作为新列表视图被添加到同步装置初始滚动位置。
到目前为止依然存在的唯一问题是s1ni5t3r上述带出来的一个。 如果您双击一扔ListView控件,然后他们仍然会断开连接。
public class ListScrollSyncer
implements AbsListView.OnScrollListener, OnTouchListener, OnGestureListener
{
private GestureDetector gestureDetector;
private Set<ListView> listSet = new HashSet<ListView>();
private ListView currentTouchSource;
private int currentOffset = 0;
private int currentPosition = 0;
public void addList(ListView list)
{
listSet.add(list);
list.setOnTouchListener(this);
list.setSelectionFromTop(currentPosition, currentOffset);
if (gestureDetector == null)
gestureDetector = new GestureDetector(list.getContext(), this);
}
public void removeList(ListView list)
{
listSet.remove(list);
}
public boolean onTouch(View view, MotionEvent event)
{
ListView list = (ListView) view;
if (currentTouchSource != null)
{
list.setOnScrollListener(null);
return gestureDetector.onTouchEvent(event);
}
else
{
list.setOnScrollListener(this);
currentTouchSource = list;
for (ListView list : listSet)
if (list != currentTouchSource)
list.dispatchTouchEvent(event);
currentTouchSource = null;
return false;
}
}
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)
{
if (view.getChildCount() > 0)
{
currentPosition = view.getFirstVisiblePosition();
currentOffset = view.getChildAt(0).getTop();
}
}
public void onScrollStateChanged(AbsListView view, int scrollState) { }
// GestureDetector callbacks
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { return false; }
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { return false; }
public boolean onSingleTapUp(MotionEvent e) { return true; }
public boolean onDown(MotionEvent e) { return true; }
public void onLongPress(MotionEvent e) { }
public void onShowPress(MotionEvent e) { }
}
编辑:双一扔问题可以通过使用状态变量来解决。
private boolean scrolling;
public boolean onDown(MotionEvent e) { return !scrolling; }
public void onScrollStateChanged(AbsListView view, int scrollState)
{
scrolling = scrollState != SCROLL_STATE_IDLE;
}
Answer 4:
我改变的ListView到RecyclerView解决它,使用RecyclerView .addOnScrollListener同步滚动事件。 并没有差异,这是完美的!
private void syncScrollEvent(RecyclerView leftList, RecyclerView rightList) {
leftList.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return rightList.getScrollState() != RecyclerView.SCROLL_STATE_IDLE;
}
});
rightList.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return leftList.getScrollState() != RecyclerView.SCROLL_STATE_IDLE;
}
});
leftList.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (recyclerView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
rightList.scrollBy(dx, dy);
}
}
});
rightList.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (recyclerView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
leftList.scrollBy(dx, dy);
}
}
});
}
Answer 5:
据山姆说明我开发了一个简单的应用中展示滚动2名列表视图在一起。 其实我的主要目的是建立与固定/冻结列并在其上完成工作时,水平滚动的ListView的扩张,将很快分享https://github.com/huseyinDaVinci/Android/tree/master/FrozenListViews
Answer 6:
尝试下面的解决方案它的作品在我的情况
leftlist.setOnScrollListener(new SyncedScrollListener(rightlist));
rightlist.setOnScrollListener(new SyncedScrollListener(leftlist));
SyncedScrollListener.java
package com.xorbix.util;
import android.view.View;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
public class SyncedScrollListener implements OnScrollListener{
int offset;
int oldVisibleItem = -1;
int currentHeight;
int prevHeight;
private View mSyncedView;
public SyncedScrollListener(View syncedView){
if(syncedView == null){
throw new IllegalArgumentException("syncedView is null");
}
mSyncedView = syncedView;
}
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
int[] location = new int[2];
if(visibleItemCount == 0){
return;
}
if(oldVisibleItem != firstVisibleItem){
if(oldVisibleItem < firstVisibleItem){
prevHeight = currentHeight;
currentHeight = view.getChildAt(0).getHeight();
offset += prevHeight;
}else{
currentHeight = view.getChildAt(0).getHeight();
View prevView;
if((prevView = view.getChildAt(firstVisibleItem - 1)) != null){
prevHeight = prevView.getHeight();
}else{
prevHeight = 0;
}
offset -= currentHeight;
}
oldVisibleItem = firstVisibleItem;
}
view.getLocationOnScreen(location);
int listContainerPosition = location[1];
view.getChildAt(0).getLocationOnScreen(location);
int currentLocation = location[1];
int blah = listContainerPosition - currentLocation + offset;
mSyncedView.scrollTo(0, blah);
}
public void onScrollStateChanged(AbsListView view, int scrollState) {
// TODO Auto-generated method stub
}
}
文章来源: Android. Scrolling 2 listviews together