动态设置Listview高度后正确检测Listview中的setOnScrollListener
Detect setOnScrollListener in Listview properly after setting Listview height dynamically
我在 Viewpager 中使用 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 高度,这段代码效果很好。
我应该在这里更改什么以使其工作或任何替代解决方案以获得期望的结果?
任何帮助将不胜感激。
But the problem is when I am setting listview height dynamically its making current listview item visible
动态设置高度不是问题。相反,问题是您通过计算列表中每个项目的高度将列表视图的高度设置为列表视图的最大可能高度。所以会发生的是列表视图的所有项目将立即填充并在列表中保持膨胀。(注意:现在不会发生视图回收)
That's why getting (calling method to get data) automatically
发生调用是因为您正在根据列表中的项目总数设置列表视图的高度。因此,列表视图中的所有元素在任何给定时间点都将处于可见状态。这意味着你的情况
if (finalItem == totalItemCount){}
将始终为真,因为您的 visibleItemCount 将始终为 totalItemCount,这使得您的最终项目始终等于 totalItemCount。 (您可以通过调试您的应用来验证这一点)。
What should I change here to make it work or any alternative solution to get desire result?
我能想到的最好的解决方案是当且仅当您根据所有项目的高度计算出的总高度小于屏幕高度时设置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
,当前可见的项目数是否为可见。
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);
}
}
}
我们在activity中这样使用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;
}
}
这里我们所做的是检查最后一个与滚动视图边界绑定的项目,如果视图可见,那么我们就在底部,所以添加更多项目。
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>
我在 Viewpager 中使用 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 高度,这段代码效果很好。 我应该在这里更改什么以使其工作或任何替代解决方案以获得期望的结果?
任何帮助将不胜感激。
But the problem is when I am setting listview height dynamically its making current listview item visible
动态设置高度不是问题。相反,问题是您通过计算列表中每个项目的高度将列表视图的高度设置为列表视图的最大可能高度。所以会发生的是列表视图的所有项目将立即填充并在列表中保持膨胀。(注意:现在不会发生视图回收)
That's why getting (calling method to get data) automatically
发生调用是因为您正在根据列表中的项目总数设置列表视图的高度。因此,列表视图中的所有元素在任何给定时间点都将处于可见状态。这意味着你的情况
if (finalItem == totalItemCount){}
将始终为真,因为您的 visibleItemCount 将始终为 totalItemCount,这使得您的最终项目始终等于 totalItemCount。 (您可以通过调试您的应用来验证这一点)。
What should I change here to make it work or any alternative solution to get desire result?
我能想到的最好的解决方案是当且仅当您根据所有项目的高度计算出的总高度小于屏幕高度时设置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
,当前可见的项目数是否为可见。
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);
}
}
}
我们在activity中这样使用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;
}
}
这里我们所做的是检查最后一个与滚动视图边界绑定的项目,如果视图可见,那么我们就在底部,所以添加更多项目。
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>