Scrollview中的Webview

Dmi*_*riy 29 android scrollview webview

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

<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>
Run Code Online (Sandbox Code Playgroud)

我从后端获得了一些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");
Run Code Online (Sandbox Code Playgroud)

有时,当页面加载时,scrollview会滚动到webview开始的位置.我不知道如何解决这个问题.

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

有时我滚动时,scrollview的滚动条会随机抽搐......

我知道将webview放入scrollview是不对的,但似乎我没有别的选择.有人能建议将所有视图和所有HTML内容放到webview上吗?

Evg*_*urg 18

使用:

android:descendantFocusability="blocksDescendants"
Run Code Online (Sandbox Code Playgroud)

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

使用:

webView.clearView();
mNewsContent.requestLayout();
Run Code Online (Sandbox Code Playgroud)

每次更改WebView大小以使布局无效时,这将删除空间距.


sve*_*ven 16

更新2014-11-13:由于Android KitKat下面描述的解决方案都不起作用 - 您需要寻找不同的方法,例如Manuel Peinado的FadingActionBar,它为WebViews提供滚动标题.

更新2012-07-08: "Nobu游戏"亲切地创建了一个TitleBarWebView类,将预期的行为带回Android Jelly Bean.当在旧平台上使用setEmbeddedTitleBar()时,它将使用隐藏方法,当在Jelly Bean或更高版本上使用时,它将模仿相同的行为.源代码在Google代码的Apache 2许可下提供

更新2012-06-30:好像该setEmbeddedTitleBar()方法已在Android 4.1 aka Jelly Bean中删除:-(

原始答案:

可能的放置WebView到一个ScrollView和它的工作.我在Android 1.6设备上的GoodNews中使用它.主要缺点是用户不能滚动"对角线"含义:如果网页内容超过屏幕宽度,ScrollView则负责WebView水平滚动的垂直滚动.由于只有其中一个处理触摸事件,您可以水平垂直滚动,但不能对角线滚动.

此外,您所描述的还有一些恼人的问题(例如,加载小于前一个内容时的空白垂直空间).我在GoodNews中找到了所有这些的解决方法,但现在不记得了,因为我找到了一个更好的解决方案:

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

此方法允许您将布局嵌入到WebView将放置在Web内容上方的布局中.当垂直滚动时,此布局将滚出屏幕,但当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));
    }
}
Run Code Online (Sandbox Code Playgroud)

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

<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"
        />
Run Code Online (Sandbox Code Playgroud)

在代码中的其他地方,您可以setTitle()使用要嵌入到的布局的ID 调用方法WebView.


Poi*_*ull 9

这是WebView的实现,其顶部包含另一个"标题栏"视图.

看起来如何:

红色条+ 3个按钮是"标题栏",下面是网页视图,所有都滚动并在一个矩形中剪切在一起.

它干净,简洁,从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();
   }
}
Run Code Online (Sandbox Code Playgroud)

用法:将标题栏视图层次结构放在布局xml中的<WebView>元素内.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>
Run Code Online (Sandbox Code Playgroud)

注意使用layerType ="software",在API 11+上的硬件中的WebView没有正确设置动画并在具有hw层时绘制.

滚动效果很好,点击标题栏,点击网页,在网页上选择文字等.


rus*_*t0R 5

谢谢你的问题,@ Dmitriy!并且非常感谢@sven的答案.

但我希望有一个解决方法,我们需要将WebView放在ScrollView中.正如sven正确注意到的主要问题是滚动视图拦截了可用于垂直滚动的所有触摸事件.所以解决方法很明显 - ViewGroup.onInterceptTouchEvent(MotionEvent e)以滚动视图容忍它的子视图的方式扩展滚动视图和覆盖方法:

  1. 处理可用于垂直滚动的所有触摸事件.
  2. 将所有这些内容分发给子视图.
  3. 仅拦截垂直滚动的事件(dx = 0,dy> 0)

当然,这种解决方案只能与适当的布局配合使用.我做了样本布局,可以说明主要的想法.

    <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>
Run Code Online (Sandbox Code Playgroud)

因此,主要思想本身是通过将所有视图(标题,webview,页脚)放在垂直线性布局中,并正确调度触摸事件以允许水平和对角滚动来避免垂直滚动冲突.我不确定它是否有用,但我已经使用TolerantScrollView和布局示例创建了示例项目,您可以在此处下载.

更重要的是 - 我已经通过反射访问封闭的API来查看解决方案,我想它相当糟糕.由于在带有Android ICS的某些HTC设备上的webview上的灰色矩形工件,它也不适用于我.也许有人知道问题是什么以及我们如何解决它?