我的活动显示ListView
。 ListView
中的每个项目都是由LinearLayout
组成的WebView
。列表中可能有数百个项目,每个项目的高度不同。
第一个问题是,在getView()
重新使用循环播放的视图时,新视图始终是原始视图的高度,即使我为{{1}设置layout_height
也是如此}和LinearLayout
到WebView
。
第二个问题是wrap_content
似乎是为列表中的每个项目调用,即使只有前五个或六个适合屏幕。我在使用其他列表项类型时没有看到这个。例如,在另一个地方我是一个高度相同的自定义视图列表,我只看到getView()
被调用最初适合屏幕的视图数量。
所以...我需要弄清楚如何强制回收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>
这是我的适配器中的getView()。 HTML片段现在来自一系列字符串。
<?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>
答案 0 :(得分:4)
我认为问题在于,使用您编写的代码系统首先测量容器高度(行linear_layout),然后测量内容(WebView)。但是第二个测量不会影响第一个测量,直到你调用invalidate或一些使容器重新计算其大小的方法。
关于为什么多次调用getView方法,请检查适配器的getViewTypeCount()方法。
@Override
public int getViewTypeCount()
{
return NumberOfTypeOfViewsInYourList;
}
“此方法返回的数量 将由其创建的视图类型 getView(int,View,ViewGroup)。每 type表示一组视图 可以在getView中转换(int,View, ViewGroup中)。如果适配器总是 为所有人返回相同类型的View 项目,此方法应返回1。 此方法仅在调用时调用 当适配器设置在 适配器视图“。
我遇到了这个方法的问题,给了一个很大的数字(比如5000)使我的应用程序崩溃,看起来它在内部用于一些ListView计算。
希望它有所帮助。
顺便说一句,关于the world of ListViews 的讨论非常好答案 1 :(得分:3)
我的ExpandableListView遇到了同样的问题。从其他帖子看,似乎是一个持续存在的问题,在一个列表中有多个webview。我找到的工作是在第一次调用getView时创建和调用wewViews,然后在正确的索引处返回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
答案 2 :(得分:3)
我尝试过sirFunkenstine的解决方案,效果很好。只有我正在构建此应用程序的客户端不喜欢这种性能。而且我不得不承认它不是那么顺利。
似乎添加和删除预装的WebViews所在的问题。每次应用程序添加/删除下一行的新WebView时,UI都会被冻结一段时间。
<强>解决方案强>
所以我认为最好只调整WebView的内容和高度而不是添加/删除。这样我们只有大量当前在内存中可见的WebView。我们可以使用ListView / Adapter的重用功能。
所以我在ListView后面添加了一个WebView,它不断计算下一个项目的WebView高度。您可以使用WebView方法getContentHeight获取高度。您必须在onPageFinished方法中执行此操作,以便获得最终高度。这引发了另一个问题,因为当使用loadDataWithBaseURL或loadData方法加载内容时,该方法返回零。似乎最终设置了值,但是在调用onPageFinished时尚未设置。为了解决这个问题,你可以添加一个线程,不断检查getContentHeight是否不再为零。如果它不为零则设置该值,您可以加载下一个。
整个解决方案有点笨拙,但它给了我一个漂亮而流畅的ListView,包括不同高度的WebView。
一些示例代码:
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);
}
}
};
答案 3 :(得分:1)
对于我的问题,我的解决方案(即使我把赏金放在上面)是将ImageView放入FrameLayout,而不是聪明地增长。
使视图无效或强制布局计算对我没有任何作用,但imageview的framelayout容器似乎解决了所有问题。我认为这种行为是错误的,但解决方法很简单。
也许同样适用于OP的webview。