动态设置Listview高度后,在Listview中正确检测setOnScrollListener

时间:2016-05-16 10:24:18

标签: android listview onscrolllistener

我在Viewpager中使用listview,我需要根据子项设置ListView高度,当用户滚动到Listview的最后位置时我需要添加新项目。但问题是当我动态设置listview高度时,它使当前列表视图项可见(或选中)。这就是为什么自动获取(调用获取数据的方法)的原因。 代码如下:

int index = lvNetwork.getFirstVisiblePosition();
    View v = lvNetwork.getChildAt(0);
    int top = (v == null) ? 0 : v.getTop();

    adapter = new NetworkAdapter(activity, R.layout.network_custom_row, networkDataArrayList);
    adapter.notifyDataSetChanged();
    lvNetwork.setAdapter(adapter);
    Utils.setlistViewHeight(lvNetwork, activity);

    lvNetwork.setSelectionFromTop(index, top);

    lvNetwork.setOnScrollListener(new AbsListView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {

        }

        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

            int finalItem = firstVisibleItem + visibleItemCount;

            Log.d("dataCalling", "visible " + finalItem);
            Log.d("dataCalling", "total " + totalItemCount);

            if (finalItem == totalItemCount) {

                if (preLast != finalItem) {
                    preLast = finalItem;
                    Log.d("dataCalling", String.valueOf(totalItemCount));
                    Log.d("dataCalling", "Page " + nextid);
                    progressBar.setVisibility(View.VISIBLE);

                      getNetworkFeed();

                }
            }
        }
    });
在Utils中使用

setlistviewHeight方法,

public static void setlistViewHeight(ListView listView, Context context) {

    ListAdapter myListAdapter = listView.getAdapter();

    if (myListAdapter == null) {
        return;
    }

    int totalHeight = 0;
    for (int size = 0; size < myListAdapter.getCount(); size++) {

        View listItem = myListAdapter.getView(size, null, listView);
        if (listItem instanceof ViewGroup)
            listItem.setLayoutParams(new RelativeLayout.LayoutParams(
                    RelativeLayout.LayoutParams.WRAP_CONTENT,
                    RelativeLayout.LayoutParams.WRAP_CONTENT));

        WindowManager wm = (WindowManager) context
                .getSystemService(Context.WINDOW_SERVICE);
        Display display = wm.getDefaultDisplay();
        @SuppressWarnings("deprecation")
        int screenWidth = display.getWidth();
        int listViewWidth = screenWidth - 65;
        int widthSpec = View.MeasureSpec.makeMeasureSpec(listViewWidth,
                View.MeasureSpec.AT_MOST);
        listItem.measure(widthSpec, 0);

        totalHeight += listItem.getMeasuredHeight();
    }

    ViewGroup.LayoutParams params = listView.getLayoutParams();
    params.height = totalHeight
            + (listView.getDividerHeight() * (myListAdapter.getCount()));
    listView.setLayoutParams(params);
    listView.requestLayout();
}

***如果我不需要动态设置listview高度,这段代码很有用。 我应该在这里做些什么来使它成功?或者任何其他解决方案来获得欲望结果?

任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:2)

  

但问题是当我动态设置listview高度时,它使当前listview项可见

动态设置高度不是问题。相反,问题是您通过计算列表中每个项目的高度将列表视图的高度设置为列表视图的最大可能高度。那么将会发生什么,列表视图的所有项目将立即填充,并将在列表中保持膨胀。(注意:现在不会进行视图回收)

  

这就是为什么自动获取(调用获取数据的方法)的原因

正在进行通话,因为您要根据列表中的项目总数设置列表视图的高度。发生这种情况的原因是,listview中的所有元素在任何给定的时间点都处于可见状态。这意味着你的状况

if (finalItem == totalItemCount){}

将始终为true,因为您的visibleItemCount将始终为totalItemCount,这使您的最终项始终等于totalItemCount。 (您可以通过调试应用来验证这一点。)

  

我应该在这里做些什么来使它成功?或者任何其他解决办法来获得欲望的结果?

我能想到的最佳解决方案是设置listview的高度当且仅当您根据所有项目的高度计算的总高度小于屏幕的高度时。否则,将列表视图的高度设置为MATCH_PARENT

ViewGroup.LayoutParams params = listView.getLayoutParams();
        Display display = getWindowManager().getDefaultDisplay();
        Point size = new Point();
        display.getSize(size);
        int height = size.y;
        if(totalHeight > height){
            params.height = ViewGroup.LayoutParams.MATCH_PARENT;
        }else {
            Log.d("", "");
            params.height = totalHeight
                    + (listView.getDividerHeight() * (myListAdapter.getCount()));
        }

因此,此代码会阻止列表视图的所有视图变为可见,因此您将收到onScroll visibleItemCount,当前可见的项目是否会显示。

答案 1 :(得分:0)

Ankit已经向您解释了代码的问题,让我与您分享一个替代解决方案。

当您已经填充其项目时,使用listview并不好用,所以最好使用scrollview并动态添加项目。 Scrollview没有滚动侦听器,因此我们将其自定义为一个。

MyScrollView.Java

public class MyScrollView extends ScrollView {

public interface OnScrollListener {
    void onScrollChanged(int l, int t, int oldl, int oldt);
}

private OnScrollListener onScrollListener;

public OnScrollListener getOnScrollListener() {
    return onScrollListener;
}

public void setOnScrollListener(OnScrollListener onScrollListener) {
    this.onScrollListener = onScrollListener;
}

public MyScrollView(Context context) {
    super(context);
}

public MyScrollView(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
    super.onScrollChanged(l, t, oldl, oldt);

    if (onScrollListener != null) {
        onScrollListener.onScrollChanged(l, t, oldl, oldt);
    }
}
}

我们在这样的活动中使用scrolllistener -

import android.graphics.Rect;
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;

public class NewScrollActivity extends AppCompatActivity {

private MyScrollView scrollView;
private LinearLayout container;
private ProgressBar progressBar;
int maxItem = 20;
private View lastItemView;
boolean alreadyExecutingRequest = false;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_new_scroll);

    progressBar = (ProgressBar) findViewById(R.id.progressBar);
    scrollView = (MyScrollView) findViewById(R.id.scrollView);
    scrollView.setOnScrollListener(scrollListener);
    container = (LinearLayout) findViewById(R.id.container);

    addItemsAsynchronously();
}

private MyScrollView.OnScrollListener scrollListener = new    MyScrollView.OnScrollListener() {
    @Override
    public void onScrollChanged(int l, int t, int oldl, int oldt) {

        if (lastItemView != null && !alreadyExecutingRequest) {
            Rect scrollBounds = new Rect();
            scrollView.getHitRect(scrollBounds);
            if (lastItemView.getLocalVisibleRect(scrollBounds)) {
                // Any portion of the lastitem view, even a single pixel, is within the visible window
                addItemsAsynchronously();
            }
        }
    }
};

private void addItemsAsynchronously() {

    new AsyncTask<Void,Void,Void>() {

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            progressBar.setVisibility(View.VISIBLE);
            alreadyExecutingRequest = true;
        }

        @Override
        protected Void doInBackground(Void... voids) {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);

            progressBar.setVisibility(View.GONE);
            addItemsToContainer();
            alreadyExecutingRequest = false;
        }


    }.execute();
}

private void addItemsToContainer() {
    int lastAddedItem = container.getChildCount();
    for (int i=lastAddedItem;i<maxItem;i++) {
        View view = LayoutInflater.from(this).inflate(R.layout.new_item, null);
        TextView textView = (TextView) view.findViewById(R.id.textView);
        textView.setText("Item - " + i);

        container.addView(view);
    }
    lastItemView = container.getChildAt(container.getChildCount() -1);
    maxItem+=10;
}
}

我们在这里做的是检查了与scrollview边界绑定的最后一个项目,因此视图可见,然后我们在底部,所以添加更多项目。

activity_new_scroll.xml

<?xml version="1.0" encoding="utf-8"?>
<com.sj.textinputlayout.MyScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/scrollView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.sj.textinputlayout.NewScrollActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <LinearLayout
            android:id="@+id/container"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical" />

        <ProgressBar android:id="@+id/progressBar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:visibility="gone"
            android:layout_gravity="center_horizontal"/>
    </LinearLayout>

</com.sj.textinputlayout.MyScrollView>

new_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:padding="10dp"
    android:layout_height="wrap_content">

    <TextView android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>