我在ListView
中有ScrollView
来显示评论,我想执行以下操作:
当用户向下滑动时,首先ScrollView
应完全向下滚动,因为列表位于底部。一旦完全关闭,Listiew
应该开始滚动。
同样,当用户向上滚动时,首先ListView
(此处颠倒的顺序!)应该在ScrollView
开始滚动之前向上滚动。
到目前为止,我已完成以下工作:
listView.setOnTouchListener(new View.OnTouchListener() {
// Setting on Touch Listener for handling the touch inside ScrollView
@Override
public boolean onTouch(View v, MotionEvent event) {
// If going up but the list is already at up, return false indicating we did not consume it.
if(event.getAction() == MotionEvent.ACTION_UP) {
if (listView.getChildCount() == 0 && listView.getChildAt(0).getTop() == 0) {
Log.e("Listview", "At top!");
return false;
}
}
// Similar behaviour but when going down check if we are at the bottom.
if( event.getAction() == MotionEvent.ACTION_DOWN) {
if (listView.getLastVisiblePosition() == listView.getAdapter().getCount() - 1 &&
listView.getChildAt(listView.getChildCount() - 1).getBottom() <= listView.getHeight()) {
Log.e("Listview","At bottom!");
v.getParent().requestDisallowInterceptTouchEvent(false);
return false;
}
}
v.getParent().requestDisallowInterceptTouchEvent(true);
return false;
}
});
日志会在合适的时刻触发,但即使我返回false,ScrollView
也不会移动。
我还尝试在语句中添加v.getParent().requestDisallowInterceptTouchEvent(false);
,但这也不起作用。
我怎样才能让它发挥作用?
答案 0 :(得分:8)
您可以创建自定义ScrollView
和ListView
并覆盖
onInterceptTouchEvent(MotionEvent event)
像这样:
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
View view = (View) getChildAt(getChildCount()-1);
int diff = (view.getBottom()-(getHeight()+getScrollY()));
if( event.getAction() == MotionEvent.ACTION_DOWN) {
if (diff ==0) {
return false;
}
}
return super.onInterceptTouchEvent(event);
}
这样,当ListView
位于ScrollView
时,ListView
上的每次向下触摸都将转到ListView
。
这只是一个草图实现,但我认为你可以通过做同样的事情来检测你何时处于ListView
作为一个说明,我会尝试使用ScrollView
,使用listView.addHeaderView(scrollViewContent)
添加当前内容ScrollView
作为ListView的标题使用ListView
,从而尝试更轻松的实现。我不知道这是否符合您的需求。
编辑:
检测何时应开始滚动ScrollView
。在ListView
中保留ScrollView
的引用。当用户向上滚动并且private void init(){
ViewConfiguration vc = ViewConfiguration.get(getContext());
mTouchSlop = vc.getScaledTouchSlop();
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
final int action = MotionEventCompat.getActionMasked(event);
switch (action) {
case MotionEvent.ACTION_DOWN:{
yPrec = event.getY();
}
case MotionEvent.ACTION_MOVE: {
final float dy = event.getY() - yPrec;
if (dy > mTouchSlop) {
// Start scrolling!
mIsScrolling = true;
}
break;
}
}
if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
mIsScrolling = false;
}
// Calculate the scrolldiff
View view = (View) getChildAt(getChildCount()-1);
int diff = (view.getBottom()-(getHeight()+getScrollY()));
if ((!mIsScrolling || !listViewReference.listIsAtTop()) && diff == 0) {
if (event.getAction() == MotionEvent.ACTION_MOVE) {
return false;
}
}
return super.onInterceptTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
final int action = MotionEventCompat.getActionMasked(ev);
if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
mIsScrolling = false;
}
return super.onTouchEvent(ev);
}
public void setListViewReference(MyListView listViewReference) {
this.listViewReference = listViewReference;
}
位于顶部时,public boolean listIsAtTop() {
if(getChildCount() == 0) return true;
return (getChildAt(0).getTop() == 0 && getFirstVisiblePosition() ==0);
}
将使用该事件。
SET XACT_ABORT ON
ListView中的listIsAtTop方法如下所示:
SET NOCOUNT ON
答案 1 :(得分:4)
您不应将ListView放在ScrollView中,但可以使用ExpandableHeightListView来达到您的要求。这将在ScrollView中创建全高Listview。无需添加TouchListener。
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<!-- your content -->
</RelativeLayout>
<my.widget.ExpandableHeightListView
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</ScrollView>
另一种达到要求的方法是使用标题RecyclerView。
答案 2 :(得分:0)
试试这个:
首先查看是否到达了scrollview Bottom。将onScrollChanged注册到滚动视图
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt)
{
// Grab the last child placed in the ScrollView, we need it to determinate the bottom position.
View view = (View) getChildAt(getChildCount()-1);
// Calculate the scrolldiff
int diff = (view.getBottom()-(getHeight()+getScrollY()));
// if diff is zero, then the bottom has been reached
if( diff == 0 )
{
// notify that we have reached the bottom
// Add code here to start scrolling the ListView
Log.d(ScrollTest.LOG_TAG, "MyScrollView: Bottom has been reached" );
}
super.onScrollChanged(l, t, oldl, oldt);
}
检查您是否到达ListView的顶部。检查firstVisibleItem是否为0: -
tableListView.setOnScrollListener(new OnScrollListener() {
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if (visibleItemCount == 0)
// you have reached at top of lustView
{
java.lang.System.out.println("you have reached at top of lustView!");
}
else {
if ((firstVisibleItem + visibleItemCount) == totalItemCount) {
// put your stuff here
java.lang.System.out.println("end of the line reached!");
}
}
}
});
我希望这适合你。如果遇到任何问题,请告诉我。