2012-03-15 99 views
29

我必须将WebView放入ScrollView中。但是我必须在webview之前将一些视图放到同一个scrollview中。所以它看起来像这样:Scrollview中的Webview

<ScrollView 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    > 
<LinearLayout 
    android:id="@+id/articleDetailPageContentLayout" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    android:orientation="vertical"> 
    <LinearLayout 
     android:id="@+id/articleDetailRubricLine" 
     android:layout_width="fill_parent" 
     android:layout_height="3dip" 
     android:background="@color/fashion"/> 

    <ImageView 
     android:id="@+id/articleDetailImageView" 
     android:layout_width="fill_parent" 
     android:layout_height="wrap_content" 
     android:adjustViewBounds="true" 
     android:scaleType="fitStart" 
     android:src="@drawable/article_detail_image_test"/> 

    <TextView 
     android:layout_width="fill_parent" 
     android:layout_height="wrap_content" 
     android:padding="5dip" 
     android:text="PUBLISH DATE"/> 

    <WebView 
     android:id="@+id/articleDetailContentView" 
     android:layout_width="fill_parent" 
     android:layout_height="wrap_content" 
     android:background="@color/fashion" 
     android:isScrollContainer="false"/> 
</LinearLayout> 

我越来越从后端一些HTML信息。它没有任何主体标签或标签,只是由<p><h4>或其他一些标签包围的数据。在那里也有<img>标签。有时对于当前屏幕宽度,图片太宽。所以我在HTML的开头添加了一些CSS。所以,我加载数据的WebView这样的:

private final static String WEBVIEW_MIME_TYPE = "text/html"; 
    private final static String WEBVIEW_ENCODING = "utf-8"; 
String viewport = "<head><meta name=\"viewport\" content=\"target-densitydpi=device-dpi\" /></head>"; 
     String css = "<style type=\"text/css\">" + 
      "img {width: 100%;}" + 
      "</style>"; 
     articleContent.loadDataWithBaseURL("http://", viewport + css + articleDetail.getContent(), WEBVIEW_MIME_TYPE, 
      WEBVIEW_ENCODING, "about:blank"); 

有时加载页面时,滚动视图滚动到地方的WebView开始。我不知道如何解决这个问题。

此外,webview内容之后有时会出现巨大的白色空白空间。我也不知道该怎么做。

有时滚动视图的滚动条开始抽搐随机地在我滚动...

我知道,这是不对的放置的WebView到滚动视图,但似乎我没有别的最佳的选择。任何人都可以提出将所有视图和所有HTML内容放置到webview的方法吗?

+0

使用RelativeLayout的。 – asish 2012-03-15 12:37:26

回答

16

更新2014-11-13:由于Android奇巧既不下面正在描述的解决方案 - 你将需要寻找像例如不同的方法Manuel Peinado's FadingActionBar它为WebViews提供了一个滚动标题。

更新2012-07-08:“Nobu游戏”亲切地创建了一个TitleBarWebView类,将预期行为带回Android Jelly Bean。当在较旧的平台上使用时,它将使用隐藏的setEmbeddedTitleBar()方法,并且在Jelly Bean或更高版本上使用时,它将模仿相同的行为。该源代码可以在Apache 2许可证at google code

更新2012-06-30:看来好像setEmbeddedTitleBar()方法已在的Android 4被移除。1又名果冻豆:-(

原来的答复:

可以放置一个WebViewScrollView和它的工作,我在GoodNews使用这种在Android 1.6设备上的主。缺点是用户无法滚动“对角线”含义:如果网页内容超出屏幕宽度,则ScrollView负责水平滚动的WebView的垂直滚动,因为只有其中一个人处理触摸事件,您可以水平滚动垂直但不是对角最终。

此外,还有一些令人讨厌的问题,如您所描述的(例如,加载小于前一个内容的内容时为空垂直空间)。我发现变通方法真证所有的人,但不记得他们了,因为我已经找到了更好的解决方案:

如果你只把WebViewScrollView放置控件以上网站内容并且您可以只支持Android 2及更高版本,那么您可以使用WebView的隐藏内部setEmbeddedTitleBar()方法。它已经在API级别5中引入,并且(意外地?)正式公开发布(我认为它是3.0)。

此方法允许您将布局嵌入WebView中,该布局将放置在Web内容上方。这种布局将在垂直滚动时滚动屏幕,但在网页内容水平滚动时将保持在相同的水平位置。

由于此方法未由API导出,因此您需要使用Java反射来调用它。我建议派生新类如下:

public final class WebViewWithTitle extends ExtendedWebView { 
    private static final String LOG_TAG = "WebViewWithTitle"; 
    private Method setEmbeddedTitleBarMethod = null; 

    public WebViewWithTitle(Context context) { 
     super(context); 
     init(); 
    } 

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

    private void init() { 
     try { 
      setEmbeddedTitleBarMethod = WebView.class.getMethod("setEmbeddedTitleBar", View.class); 
     } catch (Exception ex) { 
      Log.e(LOG_TAG, "could not find setEmbeddedTitleBar", ex); 
     } 
    } 

    public void setTitle(View view) { 
     if (setEmbeddedTitleBarMethod != null) { 
      try { 
       setEmbeddedTitleBarMethod.invoke(this, view); 
      } catch (Exception ex) { 
       Log.e(LOG_TAG, "failed to call setEmbeddedTitleBar", ex); 
      } 
     } 
    } 

    public void setTitle(int resId) { 
     setTitle(inflate(getContext(), resId, null)); 
    } 
} 

然后在您的布局文件,你可以使用

<com.mycompany.widget.WebViewWithTitle 
     xmlns:android="http://schemas.android.com/apk/res/android" 
     android:id="@+id/content" 
     android:layout_width="fill_parent" 
     android:layout_height="fill_parent" 
     /> 

,并在你的代码别的地方有这个,你可以调用setTitle()法的ID要嵌入到WebView中的布局。

+0

“我在GoodNews找到了所有这些解决方法。”你是如何解决对角线滚动问题的? – Mark 2014-11-12 02:01:31

+0

@Mark,在这个答案中描述的解决方案基于旧的“WebView”中隐藏的特征实现了一个头部,以便对角线滚动毫无问题地工作(详见上面的细节)。不幸的是,自从JellyBean以后,这个解决方案不再有效。在答案的开头看到我的更新。 – sven 2014-11-13 14:32:56

+0

2014-11-13您的建议看起来很有希望。不幸的是,它不适用于Android 5.0以及某些4.0.X设备。 http://imgur.com/GEXzRWT我在onDraw()方法中找到ObservableWebViewWithHeader类的问题。似乎翻译方法在某些Android版本上表现有所不同。有谁知道如何解决这个问题? – Johan 2014-11-20 08:43:26

0

我知道将webview放入滚动视图是不正确的,但似乎我没有其他选择。

是的,你这样做,因为你想要的东西不能可靠地工作。

但我必须在webview之前将相同的scrollview视图。

删除ScrollView。将您的WebViewandroid:layout_height更改为fill_parentWebView将填满LinearLayout中未被其他小部件占用的所有剩余空间。

+0

如果我喜欢你说的话,只有webview区域可以滚动。但我需要使用ImageView和TextView的整个区域进行滚动。 – Dmitriy 2012-03-15 13:01:48

+0

@Dmitriy:然后将文本和图像放在HTML中,摆脱小部件,所以你只有一个'WebView',整个事情可以一致滚动。 – CommonsWare 2012-03-15 13:10:03

+0

@CommonsWare“,因为你想要的东西不能可靠地工作。”你能否详细说明一下?我和ScrollView中的WebView具有完全相同的情况,它使用不同的内容加载并且不能正确调整大小,或者ScrollView的滚动条不断地颤抖/抽搐。将所有内容放在WebView中对我来说不是一种选择。 – 2012-04-19 13:52:08

9

这里是包含另一个“标题栏”视图顶部的WebView的实现。

它的外观:

红酒吧+ 3个按钮是“标题栏”,下面是Web视图,所有的滚动,在一个长方形夹在一起。

它干净简洁,可以从API 8到16以上的所有方式工作(只需很小的努力,它也可以在API < 8上工作)。它不使用任何隐藏的函数,如WebView.setEmbeddedTitleBar。

public class TitleWebView extends WebView{ 

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

    private int titleHeight; 

    @Override 
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){ 
     super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
     // determine height of title bar 
     View title = getChildAt(0); 
     titleHeight = title==null ? 0 : title.getMeasuredHeight(); 
    } 

    @Override 
    public boolean onInterceptTouchEvent(MotionEvent ev){ 
     return true; // don't pass our touch events to children (title bar), we send these in dispatchTouchEvent 
    } 

    private boolean touchInTitleBar; 
    @Override 
    public boolean dispatchTouchEvent(MotionEvent me){ 

     boolean wasInTitle = false; 
     switch(me.getActionMasked()){ 
     case MotionEvent.ACTION_DOWN: 
     touchInTitleBar = (me.getY() <= visibleTitleHeight()); 
     break; 

     case MotionEvent.ACTION_UP: 
     case MotionEvent.ACTION_CANCEL: 
     wasInTitle = touchInTitleBar; 
     touchInTitleBar = false; 
     break; 
     } 
     if(touchInTitleBar || wasInTitle) { 
     View title = getChildAt(0); 
     if(title!=null) { 
      // this touch belongs to title bar, dispatch it here 
      me.offsetLocation(0, getScrollY()); 
      return title.dispatchTouchEvent(me); 
     } 
     } 
     // this is our touch, offset and process 
     me.offsetLocation(0, -titleHeight); 
     return super.dispatchTouchEvent(me); 
    } 

    /** 
    * @return visible height of title (may return negative values) 
    */ 
    private int visibleTitleHeight(){ 
     return titleHeight-getScrollY(); 
    }  

    @Override 
    protected void onScrollChanged(int l, int t, int oldl, int oldt){ 
     super.onScrollChanged(l, t, oldl, oldt); 
     View title = getChildAt(0); 
     if(title!=null) // undo horizontal scroll, so that title scrolls only vertically 
     title.offsetLeftAndRight(l - title.getLeft()); 
    } 

    @Override 
    protected void onDraw(Canvas c){ 

     c.save(); 
     int tH = visibleTitleHeight(); 
     if(tH>0) { 
     // clip so that it doesn't clear background under title bar 
     int sx = getScrollX(), sy = getScrollY(); 
     c.clipRect(sx, sy+tH, sx+getWidth(), sy+getHeight()); 
     } 
     c.translate(0, titleHeight); 
     super.onDraw(c); 
     c.restore(); 
    } 
} 

用法:将您的标题栏视图层次<的WebView在布局XML >元素内。 WebView继承ViewGroup,因此它可以包含子项,尽管ADT插件抱怨它不能。 实施例:

<com.test.TitleWebView 
    android:id="@+id/webView" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:layerType="software" > 

    <LinearLayout 
     android:id="@+id/title_bar" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:background="#400" > 

     <Button 
     android:id="@+id/button2" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:text="Button" /> 

     <Button 
     android:id="@+id/button3" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:text="Button" /> 

     <Button 
     android:id="@+id/button5" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:text="Button" /> 
    </LinearLayout> 
</com.test.TitleWebView> 

注layerType =“软件”,web视图在API 11+硬件使用不正确的动画和当其具有HW层绘制。

滚动完美的作品,以及标题栏上点击,点击网页,选择在网络文本等

+0

-Pointer Null这个功能非常好,但它仅适用于垂直视图,并且当方向更改为水平时,非常难以滚动。 – hemant 2014-01-22 06:21:50

+0

然而,对于大多数情况来说非常好,这不适用于文本输入和其他输入元素。 – Mdlc 2015-10-04 14:19:38

5

谢谢你的问题,@Dmitriy! 同时也非常感谢@sven的答案。

但我希望有一个解决方案,我们需要将WebView放入ScrollView中。正如sven正确地注意到的主要问题是滚动视图截取了可用于垂直滚动的所有触摸事件。所以,解决办法是显而易见的 - 延长滚动视图,并以这样的方式变得宽容它的滚动视图的子视图覆盖ViewGroup.onInterceptTouchEvent(MotionEvent e)方法:

  1. 的过程,可用于垂直滚动所有触摸事件。
  2. 将他们全部发送到子视图。
  3. 只有垂直滚动(DX = 0,DY> 0)

Ofcourse此溶液截距事件只能在夫妇来使用适当的布局。 我制作了可以说明主要想法的样本布局。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" > 

    <com.rus1f1kat0r.view.TolerantScrollView 
     android:id="@+id/scrollView1" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:layout_centerHorizontal="true" 
     android:layout_centerVertical="true" > 

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

      <TextView 
       android:id="@+id/textView1" 
       android:layout_width="wrap_content" 
       android:layout_height="wrap_content" 
       android:text="Large Text" 
       android:textAppearance="?android:attr/textAppearanceLarge" /> 

      <TextView 
       android:id="@+id/textView2" 
       android:layout_width="wrap_content" 
       android:layout_height="wrap_content" 
       android:text="Large Text" 
       android:textAppearance="?android:attr/textAppearanceLarge" /> 

      <WebView 
       android:id="@+id/webView1" 
       android:layout_width="match_parent" 
       android:layout_height="wrap_content" /> 

      <TextView 
       android:id="@+id/textView3" 
       android:layout_width="wrap_content" 
       android:layout_height="wrap_content" 
       android:text="Medium Text" 
       android:textAppearance="?android:attr/textAppearanceMedium" /> 

      <TextView 
       android:id="@+id/textView4" 
       android:layout_width="wrap_content" 
       android:layout_height="wrap_content" 
       android:text="Medium Text" 
       android:textAppearance="?android:attr/textAppearanceMedium" /> 

     </LinearLayout> 
    </com.rus1f1kat0r.view.TolerantScrollView> 
</RelativeLayout> 

使主想法本身是把所有的意见(标题,网页流量,页脚)垂直线性布局里面,以避免垂直滚动冲突,并正确地调度触摸事件,以使横向和斜向滚动。 我不确定它是否有用,但我用TolerantScrollView和布局示例创建了示例项目,可以下载它here

更重要的是 - 我查看了解决方案,通过反射访问封闭的API,我猜这是相当困难。它也不适用于我,因为Android ICS的某些HTC设备上的webview上的灰色矩形工件。也许有人知道什么是问题以及我们如何解决它?

+0

你使用透明背景吗? – Antzi 2013-06-13 15:21:28

+0

您的解决方案非常好,但它不允许正确地进行文本选择。当用户拖动选择图标垂直移动时,整个ScrollView会移动。你将如何修改你的代码来解决这个问题? – Marcin 2013-12-05 19:43:13

+0

到目前为止,我们正在研究另一种更适合开发指南的解决方案,并且具有更少的错误和不一致性。一旦准备就绪,我会向您提供代码片段。 – rus1f1kat0R 2013-12-10 07:47:08

18

使用:

android:descendantFocusability="blocksDescendants" 

在包装的布局,这将阻止WebView跳转到它的开始。

使用:

webView.clearView(); 
mNewsContent.requestLayout(); 
每次更改 WebView尺寸布局失效时间

,这将删除空的间距。

+1

+1为答案的第一部分。不幸的是,第二部分不起作用(可能是由于它不完全清楚你指的是mNewsContent的名字)。 – 2014-01-22 13:17:27

+0

android:descendantFocusability =“blocksDescendants”这个工作适合我! – Mejonzhan 2015-07-10 08:29:46

+0

如果禁用可聚焦性,则不能在web视图中使用输入字段。 – spatialist 2015-10-09 09:23:35

2

这个答案都不适用于我,所以这里是我的解决方案。首先,我们需要覆盖WebView以有能力处理它的滚动。你可以在这里找到如何做:https://stackoverflow.com/a/14753235/1285670

然后用两个视图创建你的xml,其中一个是WebView,另一个是你的标题布局。

这是我的XML代码:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" > 

    <com.project.ObservableWebView 
     android:id="@+id/post_web_view" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:background="#fff" /> 

    <LinearLayout 
     android:id="@+id/post_header" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:background="#fff" 
     android:orientation="vertical" 
     android:paddingLeft="@dimen/common_ui_space" 
     android:paddingRight="@dimen/common_ui_space" 
     android:paddingTop="@dimen/common_ui_space" > 

     ////some stuff 

    </LinearLayout> 

</FrameLayout> 

接下来是处理WebView滚动和移动适当滚动值称号。您必须在这里使用NineOldAndroids

@Override 
public void onScroll(int l, int t, int oldl, int oldt) { 
    if (t < mTitleLayout.getHeight()) { 
     ViewHelper.setTranslationY(mTitleLayout, -t); 
    } else if (oldt < mTitleLayout.getHeight()) { 
     ViewHelper.setTranslationY(mTitleLayout, -mTitleLayout.getHeight()); 
    } 
} 

并且必须添加填充到您的WebView的内容,这样就不会叠加标题:

v.getViewTreeObserver().addOnGlobalLayoutListener(
    new OnGlobalLayoutListener() { 
     @SuppressWarnings("deprecation") 
     @SuppressLint("NewApi") 
     @Override 
     public void onGlobalLayout() { 
      if (mTitleLayout.getHeight() != 0) { 
       if (Build.VERSION.SDK_INT >= 16) 
        v.getViewTreeObserver().removeOnGlobalLayoutListener(this); 
       else 
        v.getViewTreeObserver().removeGlobalOnLayoutListener(this); 
       } 

       mWebView.loadDataWithBaseURL(null, "<div style=\"padding-top: " 
        + mTitleLayout.getHeight()/dp + "px\">" + mPost.getContent() 
        + "</div>", "text/html", "UTF8", null); 
     } 
}); 
+0

* dp *这里的值是多少 – 2016-09-27 10:12:19

+0

@YogeshSeralia只是屏幕的密度。你可以从context.getResources()。getDisplayMetrics()。density' – rstk 2016-09-28 15:38:54

+0

@YogeshSeralia得到它,但是没有更好的方法来转换px和dp,使用'TypedValue.applyDimension() – rstk 2016-09-28 15:42:53