WebViews ListView – 重用不同高度的项目失败; 在显示任何视图之前请求所有视图

我有一个显示ListView的活动。 ListView中的每个项目都是一个由一个WebView组成的LinearLayout 。 列表中可能有数百个项目,每个项目都是不同的高度。

第一个问题是,当在getView()重用循环视图时,即使我已经将LinearLayoutWebViewlayout_height设置为wrap_content ,新视图始终是原始视图的高度。

第二个问题是getView()似乎被调用了列表中的每个项目,即使只有前五六个适合在屏幕上。 使用其他列表项types时我还没有看到。 例如,在另一个地方我是一个自定义视图的列表都是相同的高度,我只看到getView()被调用的最初适合在屏幕上的视图的数量。

所以…我需要弄清楚如何强制回收WebViews来渲染他们的新内容,这样他们的高度就可以被计算出来,而不仅仅是使用之前的高度。 我想知道为什么系统要求我在这种情况下我所有的项目。

以下是必需的代码片段:

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <ListView android:id="@+id/topPane" android:layout_width="fill_parent" android:layout_height="fill_parent" android:dividerHeight="1.0px" android:divider="#FFFFFF" android:smoothScrollbar="false" /> </LinearLayout> 

行从以下内容构build而成:

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="wrap_content" > <WebView android:id="@+id/rowWebView" android:layout_width="fill_parent" android:layout_height="wrap_content" android:padding="0.0px" android:scrollbars="none" /> </LinearLayout> 

这是我的适配器中的getView()。 HTML代码片段现在来自一个string数组。

  @Override public View getView(int position, View convertView, ViewGroup parent) { String item = (String) getItem(position); if (convertView == null) { convertView = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.rowview, parent, false); } WebView wv = (WebView) convertView.findViewById(R.id.rowWebView); wv.loadDataWithBaseURL(null, item, "text/html", "utf-8", "about:blank"); return convertView; } 

Solutions Collecting From Web of "WebViews ListView – 重用不同高度的项目失败; 在显示任何视图之前请求所有视图"

我认为问题在于用你编写的代码首先测量容器高度(行linear_layout),然后测量内容(WebView)。 但是,第二种方法不会影响第一个方法,直到您调用invalidate或某种方法使容器重新计算其大小。

关于为什么多次调用getView方法,请检查适配器的getViewTypeCount()方法。

 @Override public int getViewTypeCount() { return NumberOfTypeOfViewsInYourList; } 

文件指出:

“这个方法返回将由getView(int,View,ViewGroup)创build的视图types的数量,每个types表示一组可以在getView(int,View,ViewGroup)中转换的视图。相同types的查看所有项目,这个方法应该返回1.这个方法只有当适配器设置在AdapterView上时才会被调用。

我有这个方法的问题,给一个很大的数字(如5000)使我的应用程序崩溃,它看起来像它内部用于一些ListView计算。

希望它以某种方式帮助。

顺便说一句,关于ListViews的世界有一个很好的说法

我有我的ExpandableListView相同的问题。 从其他post看来,多个网页浏览在一个列表中似乎是一个持续的问题。 我发现的工作是在第一次调用getView时创build和调用wewView的数组,然后在正确的索引处返回webView。 它有更多的内存密集,但它不会导致视图的大小。

 SparseArray<WebView> wvGroup = new SparseArray<WebView>(); @Override public View getView(int position, View convertView, ViewGroup parent) { WebView wv = null; if (wvGroup.size() < 1) { for (int i = 0; i < sectionItems.size(); i++) { WebView webViewItem = new WebView(context); String htmlData = "<link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\" />" + sectionItems.get(i).child_content; webViewItem.loadDataWithBaseURL("file:///android_assets/", htmlData, "text/html", "UTF-8", null); wvGroup.append(i, webViewItem); } } wv = wvGroup.get(groupPosition); wv.setPadding(30, 10, 10, 10); return wv 

我已经尝试了sirFunkenstine的解决scheme,这很好。 只有客户,我正在build立这个应用程序,不喜欢的performance。 而我不得不承认并不那么顺利。

这似乎是添加和删除预装WebViews的问题。 每当应用程序为下一行添加/删除新的WebView时,UI都会被冻结一秒。

所以我认为最好只调整WebView的内容和高度,而不是添加/删除。 这样我们只有在内存中可见的WebViews的数量。 我们可以使用ListView / Adapter的重用function。

所以我在ListView后面添加了一个WebView,它不断计算下一个项目的WebView高度。 您可以使用WebView方法getContentHeight获取高度。 你必须在onPageFinished方法中做到这一点,所以你有最后的高度。 这引发了另一个问题,当内容使用loadDataWithBaseURL或loadData方法加载时,导致方法返回零。 看起来这个值是最终设定的,但还没有在onPageFinished被调用的时候。 为了克服这个问题,你可以添加一个线程,不断检查getContentHeight是否不为零。 如果它不是零,那么值被设置,你可以加载下一个。

这整个解决scheme是有点hacky,但它给了我一个不错的和平滑的ListView,包括不同高度的WebViews。

一些示例代码:

1:排队你要预加载的行的位置:

 private SparseArray<Integer> mWebViewHeights = new SparseArray<Integer>(); private LinkedBlockingQueue mQueue; { mQueue = new LinkedBlockingQueue(); try { mQueue.put(position); } catch (InterruptedException e) { e.printStackTrace(); } } 

2:启动Runnable不断从队列中加载新项目,并检查/添加高度到一个数组:

 Handler h; Runnable rowHeightCalculator = new Runnable() { h = new Handler(); rowHeightCalculator.run(); } 

3:加载新的HTML内容并检查高度:

 Handler h; Runnable rowHeightCalculator = new Runnable() { int mCurrentIndex = -1; boolean mLoading = false; // Read the webview height this way, cause oncomplete only returns 0 for local HTML data @Override public void run() { if(Thread.interrupted()) return; if (mCurrentIndex == -1 && mQueue.size() > 0) { try { mCurrentIndex = (Integer)mQueue.take(); String html = mItems.get(mCurrentIndex).getPart().getText(); mDummyWebView.clearView(); mDummyWebView.loadDataWithBaseURL("file:///android_asset/reader/", "THE HTML HERE", "text/html", "UTF-8", null); mLoading = true; } } catch (InterruptedException e) { e.printStackTrace(); } } if(mDummyWebView.getContentHeight() != 0 && mCurrentIndex >= 0) { int contentHeight = mDummyWebView.getContentHeight(); mWebViewHeights.append(mCurrentIndex, contentHeight); mCurrentIndex = -1; mLoading = false; } // Reload view if we loaded 20 items if ((mQueue.size() == 0 && (mItemsCount - mQueue.size()) < 20) || (mItemsCount - mQueue.size()) == 20) { notifyDataSetChanged(); } if (mQueue.size() > 0 || mLoading) { h.postDelayed(this, 1); } } }; 

我的解决scheme(即使我把奖金),我的问题是将ImageView放入一个FrameLayout,而不是智能增长。

使视图无效或强制布局计算对我没有任何帮助,但是imageview的framelayout容器似乎解决了所有问题。 我认为这种行为是错误的,但解决方法很简单。

也许这同样适用于OP的webview。