Can't scroll over image in webview

2020-04-16 07:22发布

问题:

I developed a webview app for android and iOS. I noticed that I can't scroll over a specific html element in the android app, while it works on iOS.

This is the website.

The problem is on the product image but only on the products detail page where you can buy the product and put it into your cart...

HTML

<div class="magic-slide mt-active" data-magic-slide="zoom">
    <a id="MagicZoomPlusImage286" class="MagicZoom" href="https://www.blizz-z.de/media/catalog/product/cache/2/image/0dc2d03fe217f8c83829496872af24a0/f/l/fliesenkleber-proflex-fix-1303_1.jpg" data-options="selectorTrigger:hover;textHoverZoomHint:Hovern zum Zoomen;textClickZoomHint:Berühren zum Zoomen;textExpandHint:Vergrößern;"
        data-mobile-options="textHoverZoomHint:Berühren zum Zoomen;textClickZoomHint:Doppeltippe zum Zoomen;textExpandHint:Vergrößern;">
        <figure class="mz-figure mz-hover-zoom mz-ready"><img itemprop="image" src="https://www.blizz-z.de/media/catalog/product/cache/2/image/450x450/0dc2d03fe217f8c83829496872af24a0/f/l/fliesenkleber-proflex-fix-1303_1.jpg" alt="Fliesenkleber proflex fix Schnell-Fliesenkleber - nach 3 Stunden begehbar"
                style="max-width: 450px; max-height: 450px;">
            <div class="mz-lens" style="top: 0px; transform: translate(-10000px, -10000px); width: 122px; height: 122px;"><img src="https://www.blizz-z.de/media/catalog/product/cache/2/image/450x450/0dc2d03fe217f8c83829496872af24a0/f/l/fliesenkleber-proflex-fix-1303_1.jpg" style="position: absolute; top: 0px; left: 0px; width: 349px; height: 349px; transform: translate(-1px, -132px);"></div>
            <div
                class="mz-loading"></div>
<div class="mz-hint mz-hint-hidden"><span class="mz-hint-message">Vergrößern</span></div>
</figure>
</a>
</div>

If I visit the website from the smartphones chrome browser then it works, so it must be a bug in webview?

The image is a slider, I can slide left and right but I can't scroll down the page if I scroll at the image.

FullscreenActivity.java:

package de.blizz_z.onlineshop;

import android.annotation.SuppressLint;
import android.content.Intent;
import android.graphics.Bitmap;
import android.webkit.URLUtil;
import android.net.Uri;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Build;
import android.os.Handler;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.webkit.WebChromeClient;
import android.widget.Button;
import android.util.Log;
import android.webkit.HttpAuthHandler;
import android.webkit.ValueCallback;

/**
 * An example full-screen activity that shows and hides the system UI (i.e.
 * status bar and navigation/system bar) with user interaction.
 */
public class FullscreenActivity extends AppCompatActivity
{
    private WebView blizzView;
    private Button backButton;
    private String website;

    /**
     * Whether or not the system UI should be auto-hidden after
     * {@link #AUTO_HIDE_DELAY_MILLIS} milliseconds.
     */
    private static final boolean AUTO_HIDE = true;

    /**
     * If {@link #AUTO_HIDE} is set, the number of milliseconds to wait after
     * user interaction before hiding the system UI.
     */
    private static final int AUTO_HIDE_DELAY_MILLIS = 3000;

    /**
     * Some older devices needs a small delay between UI widget updates
     * and a change of the status and navigation bar.
     */
    private static final int UI_ANIMATION_DELAY = 300;
    private final Handler mHideHandler = new Handler();
    private final Runnable mHidePart2Runnable = new Runnable()
    {
        @SuppressLint("InlinedApi")
        @Override
        public void run() {

        }
    };

    private final Runnable mShowPart2Runnable = new Runnable()
    {
        @Override
        public void run() {
            // Delayed display of UI elements
            ActionBar actionBar = getSupportActionBar();
            if (actionBar != null) {
                actionBar.show();
            }
        }
    };
    private boolean mVisible;
    private final Runnable mHideRunnable = new Runnable() {
        @Override
        public void run() {
            hide();
        }
    };

    /**
     * Touch listener to use for in-layout UI controls to delay hiding the
     * system UI. This is to prevent the jarring behavior of controls going away
     * while interacting with activity UI.
     */
    private final View.OnTouchListener mDelayHideTouchListener = new View.OnTouchListener()
    {
        @Override
        public boolean onTouch(View view, MotionEvent event)
        {

            Log.i("debug_log", "touch");

            if (AUTO_HIDE) {
                delayedHide(AUTO_HIDE_DELAY_MILLIS);
            }

            int x = (int) event.getX();
            int y = (int) event.getY();

            Log.i("debug_log", "moving: (" + x + ", " + y + ")");

            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    Log.i("debug_log", "touched down");
                    break;
                case MotionEvent.ACTION_MOVE:
                    Log.i("debug_log", "moving: (" + x + ", " + y + ")");
                    break;
                case MotionEvent.ACTION_UP:
                    Log.i("debug_log", "touched up");
                    break;
            }

            return true;
        }

    };

    @SuppressLint("ClickableViewAccessibility")
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_fullscreen);

        mVisible = true;
        website = "https://www.blizz-z.de";
        blizzView = findViewById(R.id.blizzView);

        WebSettings settings = blizzView.getSettings();
        settings.setJavaScriptEnabled(true);

        // https://developer.android.com/reference/android/webkit/WebViewClient
        blizzView.setWebViewClient(new WebViewClient() {

            @Override
            public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
                super.onReceivedHttpError(view, request, errorResponse);

                Log.i("debug_log", errorResponse.getReasonPhrase());
            }

            @Override
            public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm)
            {
                super.onReceivedHttpAuthRequest(view, handler, host, realm);

                view.setHttpAuthUsernamePassword(host, realm, "macs", "20macs14");
            }

            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon)
            {
                // check here the url
                if (url.endsWith(".pdf")) {
                    Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
                    startActivity(browserIntent);
                } else {
                    super.onPageStarted(view, url, favicon);
                }
            }

            @Override
            // Notify the host application that a page has finished loading.
            public void onPageFinished(WebView view, String url)
            {
                super.onPageFinished(view, url);

                 // Hide/Show back button
                backButton = findViewById(R.id.backButton);
                backButton.setEnabled(blizzView.canGoBack());

                if (blizzView.canGoBack()) {
                    backButton.setVisibility(View.VISIBLE);
                } else {
                    backButton.setVisibility(View.INVISIBLE);
                }

                js(blizzView, "jQuery(document).ready(function() {"

                                        + "setInterval(function() {"
                                            + "jQuery('#myInput').css('background', '#'+(Math.random()*0xFFFFFF<<0).toString(16));"

                                            + "jQuery('a').each(function() {"
                                                + "jQuery(this).removeAttr('download');"
                                            + "});"
                                        + "}, 1000);"
                                    + "});");

            }

            // Give the host application a chance to take control when a URL is about to be loaded in the current WebView.
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url)
            {
                Log.i("debug_log", "shouldOverrideUrlLoading");

                //view.loadDataWithBaseURL("https://www.blizz-z.de", );

            // Allow download of .pdf files
                if (url.endsWith(".pdf")) {
                    startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
                    // if want to download pdf manually create AsyncTask here
                    // and download file
                    return true;
                }

            // Also allow urls not starting with http or https (e.g. tel, mailto, ...)
                if( URLUtil.isNetworkUrl(url) ) {
                    return false;
                } else {
                    startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
                }

                return true;
            }

        });

        blizzView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {

                int x = (int) event.getX();
                int y = (int) event.getY();

                //WebView.HitTestResult hr = blizzView.getHitTestResult();
                //Log.i("debug_log", "getExtra = "+ hr.getExtra() + " Type= " + hr.getType());

                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        Log.i("debug_log", "touched down");
                        break;
                    case MotionEvent.ACTION_MOVE:
                        Log.i("debug_log", "moving: (" + x + ", " + y + ")");
                        break;
                    case MotionEvent.ACTION_UP:
                        Log.i("debug_log", "touched up");
                        break;
                }

                return false;
            }

        });

        // URL laden:
        blizzView.loadUrl(website);
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState)
    {
        Log.i("debug_log", "onPostCreate");
        super.onPostCreate(savedInstanceState);

        // Trigger the initial hide() shortly after the activity has been
        // created, to briefly hint to the user that UI controls
        // are available.
        delayedHide(100);
    }

    private void toggle()
    {
        if (mVisible) {
            hide();
        } else {
            show();
        }
    }

    private void hide()
    {
        // Hide UI first
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.hide();
        }
        mVisible = false;

        // Schedule a runnable to remove the status and navigation bar after a delay
        mHideHandler.removeCallbacks(mShowPart2Runnable);
        mHideHandler.postDelayed(mHidePart2Runnable, UI_ANIMATION_DELAY);
    }

    @SuppressLint("InlinedApi")

    private void show()
    {
        // Show the system bar
        mVisible = true;

        // Schedule a runnable to display UI elements after a delay
        mHideHandler.removeCallbacks(mHidePart2Runnable);
        mHideHandler.postDelayed(mShowPart2Runnable, UI_ANIMATION_DELAY);
    }

    /**
     * Schedules a call to hide() in delay milliseconds, canceling any
     * previously scheduled calls.
     */
    private void delayedHide(int delayMillis)
    {
        mHideHandler.removeCallbacks(mHideRunnable);
        mHideHandler.postDelayed(mHideRunnable, delayMillis);
    }

    public void js(WebView view, String code)
    {
        String javascriptCode = "javascript:" + code;
        if (Build.VERSION.SDK_INT >= 19) {
            view.evaluateJavascript(javascriptCode, new ValueCallback<String>() {

                @Override
                public void onReceiveValue(String response) {
                    Log.i("debug_log", response);
                }
            });
        } else {
            view.loadUrl(javascriptCode);
        }
    }

    // Event Listener ------------------------------------------------------------------------------

            public void goBack(android.view.View view)
            {
                blizzView.goBack();
            }

        // If back button of smartphone is pressed, then go back in browser history
            @Override
            public boolean onKeyDown(int keyCode, KeyEvent event)
            {
                Log.i("debug_log", "KeyDown");
                if (event.getAction() == KeyEvent.ACTION_DOWN) {
                    switch (keyCode) {
                        case KeyEvent.KEYCODE_BACK:
                            if (blizzView.canGoBack())
                                blizzView.goBack();
                            else
                                finish();
                            return true;
                    }
                }

                return super.onKeyDown(keyCode, event);
            }

}

activity_fullscreen.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/relativeLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:visibility="visible"
    tools:context="de.blizz_z.onlineshop.FullscreenActivity">

    <WebView
        android:id="@+id/blizzView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:keepScreenOn="true"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

    </WebView>

    <Button
        android:id="@+id/backButton"
        android:layout_width="90dp"
        android:layout_height="39dp"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginBottom="16dp"
        android:background="#F5EA01"
        android:enabled="false"
        android:onClick="goBack"
        android:text="Zurück"
        android:visibility="invisible"
        app:layout_constraintBottom_toBottomOf="@+id/blizzView"
        app:layout_constraintStart_toStartOf="@+id/blizzView" />

</android.support.constraint.ConstraintLayout>

回答1:

You have two options

Option One

By creating a custom listener for Touch Events on your Webview. I have modified the snippet from @fernandohur's answer on this post to match your scenario.

Create a new class (OnSwipeListener.java)

import android.view.GestureDetector;
import android.view.MotionEvent;

public class OnSwipeListener extends GestureDetector.SimpleOnGestureListener {

@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {

    // Grab two events located on the plane at e1=(x1, y1) and e2=(x2, y2)
    // Let e1 be the initial event
    // e2 can be located at 4 different positions, consider the following diagram
    // (Assume that lines are separated by 90 degrees.)
    //
    //
    //         \ A  /
    //          \  /
    //       D   e1   B
    //          /  \
    //         / C  \
    //
    // So if (x2,y2) falls in region:
    //  A => it's an UP swipe
    //  B => it's a RIGHT swipe
    //  C => it's a DOWN swipe
    //  D => it's a LEFT swipe
    //

    float x1 = e1.getX();
    float y1 = e1.getY();

    float x2 = e2.getX();
    float y2 = e2.getY();

    Direction direction = getDirection(x1,y1,x2,y2);
    return onSwipe(direction, velocityX, velocityY);
}

/** Override this method. The Direction enum will tell you how the user swiped. */
public boolean onSwipe(Direction direction, float velocityX, float velocityY){
    return false;
}

/**
 * Given two points in the plane p1=(x1, x2) and p2=(y1, y1), this method
 * returns the direction that an arrow pointing from p1 to p2 would have.
 * @param x1 the x position of the first point
 * @param y1 the y position of the first point
 * @param x2 the x position of the second point
 * @param y2 the y position of the second point
 * @return the direction
 */
public Direction getDirection(float x1, float y1, float x2, float y2){
    double angle = getAngle(x1, y1, x2, y2);
    return Direction.fromAngle(angle);
}

/**
 *
 * Finds the angle between two points in the plane (x1,y1) and (x2, y2)
 * The angle is measured with 0/360 being the X-axis to the right, angles
 * increase counter clockwise.
 *
 * @param x1 the x position of the first point
 * @param y1 the y position of the first point
 * @param x2 the x position of the second point
 * @param y2 the y position of the second point
 * @return the angle between two points
 */
public double getAngle(float x1, float y1, float x2, float y2) {

    double rad = Math.atan2(y1-y2,x2-x1) + Math.PI;
    return (rad*180/Math.PI + 180)%360;
}


public enum Direction{
    up,
    down,
    left,
    right;

    /**
     * Returns a direction given an angle.
     * Directions are defined as follows:
     *
     * Up: [45, 135]
     * Right: [0,45] and [315, 360]
     * Down: [225, 315]
     * Left: [135, 225]
     *
     * @param angle an angle from 0 to 360 - e
     * @return the direction of an angle
     */
    public static Direction fromAngle(double angle){
        if(inRange(angle, 45, 135)){
            return Direction.up;
        }
        else if(inRange(angle, 0,45) || inRange(angle, 315, 360)){
            return Direction.right;
        }
        else if(inRange(angle, 225, 315)){
            return Direction.down;
        }
        else{
            return Direction.left;
        }

    }

    /**
     * @param angle an angle
     * @param init the initial bound
     * @param end the final bound
     * @return returns true if the given angle is in the interval [init, end).
     */
    private static boolean inRange(double angle, float init, float end){
        return (angle >= init) && (angle < end);
    }
}
}

Then use in your activity...

public class FullscreenActivity extends AppCompatActivity implements View.OnTouchListener {

private WebView blizzView;
private Button backButton;
private String website;
private GestureDetector gestureDetector;

/**
 * Whether or not the system UI should be auto-hidden after
 * {@link #AUTO_HIDE_DELAY_MILLIS} milliseconds.
 */
private static final boolean AUTO_HIDE = true;

/**
 * If {@link #AUTO_HIDE} is set, the number of milliseconds to wait after
 * user interaction before hiding the system UI.
 */
private static final int AUTO_HIDE_DELAY_MILLIS = 3000;

/**
 * Some older devices needs a small delay between UI widget updates
 * and a change of the status and navigation bar.
 */
private static final int UI_ANIMATION_DELAY = 300;
private final Handler mHideHandler = new Handler();
private final Runnable mHidePart2Runnable = new Runnable()
{
    @SuppressLint("InlinedApi")
    @Override
    public void run() {

    }
};

private final Runnable mShowPart2Runnable = new Runnable()
{
    @Override
    public void run() {
        // Delayed display of UI elements
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.show();
        }
    }
};
private boolean mVisible;
private final Runnable mHideRunnable = new Runnable() {
    @Override
    public void run() {
        hide();
    }
};

@Override
public boolean onTouch(View v, MotionEvent event) {
    Log.d("SWIPER", "onTouch: ");
    gestureDetector.onTouchEvent(event);
    return false;
}
public void scrollUpwards(int scroll_speed) {
    try{
        ObjectAnimator anim = ObjectAnimator.ofInt(blizzView, "scrollY", blizzView.getScrollY(), blizzView.getScrollY() - scroll_speed);
        anim.setDuration(800).start();
    }catch (Exception ex){}
}
public void scrollDownwards(int scroll_speed) {
    try{
       // float maxScrollY = blizzView.getContentHeight() * blizzView.getScale() - blizzView.getMeasuredHeight();
       if(blizzView.getScrollY() <= 100){
           //due to the scroll animation the web page slows down at the top
           //hence we add some extra speed when user is at the top of page to prevent from
           //experiencing delay when scrolling back down
           scroll_speed += 1300;
       }
        ObjectAnimator anim = ObjectAnimator.ofInt(blizzView, "scrollY", blizzView.getScrollY(), blizzView.getScrollY() + scroll_speed);
        anim.setDuration(800).start();
    }catch (Exception ex){}
}
@SuppressLint("ClickableViewAccessibility")
@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    gestureDetector=new GestureDetector(this,new OnSwipeListener(){

        @Override
        public boolean onSwipe(Direction direction, float velocityX, float velocityY) {
          //  int scroll_jump_percentage = 60 / 100; //percent of velocity: increase(60) for faster scroll jump
            int scroll_speed =  ((int) Math.abs(velocityY)) * 60 / 100; //percent of velocity: increase(60) for faster scroll jump;
            if (direction==Direction.up){
                //do your stuff
             //   Log.d("SWIPER", "onSwipe: up");
                scrollDownwards(scroll_speed);
                Toast.makeText(getApplicationContext(),"You swiped UP ("+scroll_speed+")",Toast.LENGTH_SHORT).show();

                //we made it!
                return true;
            }
            else if (direction==Direction.down){
                //do your stuff
              //  Log.d("SWIPER", "onSwipe: down");
                scrollUpwards(scroll_speed);
                Toast.makeText(getApplicationContext(),"You swiped DOWN ("+scroll_speed+")",Toast.LENGTH_SHORT).show();

                //we made it!
                return true;
            }

            //nothing to handle here... Mr. WebView can do the rest
            return false;
        }
    });
    mVisible = true;
    website = "https://www.blizz-z.de";
    blizzView = findViewById(R.id.blizzView);
    blizzView.setOnTouchListener(this);
    WebSettings settings = blizzView.getSettings();
    settings.setJavaScriptEnabled(true);
    settings.setBuiltInZoomControls(false);

    // https://developer.android.com/reference/android/webkit/WebViewClient
    blizzView.setWebViewClient(new WebViewClient() {

        @Override
        public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
            super.onReceivedHttpError(view, request, errorResponse);

           // Log.i("debug_log", errorResponse.getReasonPhrase());
        }

        @Override
        public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm)
        {
            super.onReceivedHttpAuthRequest(view, handler, host, realm);

            view.setHttpAuthUsernamePassword(host, realm, "macs", "20macs14");
        }

        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon)
        {
            // check here the url
            if (url.endsWith(".pdf")) {
                Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
                startActivity(browserIntent);
            } else {
                super.onPageStarted(view, url, favicon);
            }
        }

        @Override
        // Notify the host application that a page has finished loading.
        public void onPageFinished(WebView view, String url)
        {
            super.onPageFinished(view, url);

            // Hide/Show back button
            backButton = findViewById(R.id.backButton);
            backButton.setEnabled(blizzView.canGoBack());

            if (blizzView.canGoBack()) {
                backButton.setVisibility(View.VISIBLE);
            } else {
                backButton.setVisibility(View.INVISIBLE);
            }

            js(blizzView, "jQuery(document).ready(function() {"

                    + "setInterval(function() {"
                    + "jQuery('#myInput').css('background', '#'+(Math.random()*0xFFFFFF<<0).toString(16));"

                    + "jQuery('a').each(function() {"
                    + "jQuery(this).removeAttr('download');"
                    + "});"
                    + "}, 1000);"
                    + "});");

            //inject script (this script would remove all event listener from product image
            // that was placed by your MagicZoom Js Library
            //TEMP FIX
           /* blizzView.loadUrl(
                    "javascript:(function() { " +
                            "var slides = document.getElementsByClassName(\"MagicZoom\");\n" +
                            "for(var i = 0; i < slides.length; i++)\n" +
                            "{\n" +
                            "var old_element = slides.item(i);\n" +
                            "old_element.href = '#';\n" +
                            "                var new_element = old_element.cloneNode(true);\n" +
                            "\t\t\t\told_element.parentNode.replaceChild(new_element, old_element);\n" +
                            "       \n" +
                            "   }" +
                            "})()");*/

        }

        // Give the host application a chance to take control when a URL is about to be loaded in the current WebView.
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url)
        {
            Log.i("debug_log", "shouldOverrideUrlLoading");

            //view.loadDataWithBaseURL("https://www.blizz-z.de", );

            // Allow download of .pdf files
            if (url.endsWith(".pdf")) {
                startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
                // if want to download pdf manually create AsyncTask here
                // and download file
                return true;
            }

            // Also allow urls not starting with http or https (e.g. tel, mailto, ...)
            if( URLUtil.isNetworkUrl(url) ) {
                return false;
            } else {
                startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
            }

            return true;
        }

    });
    // URL laden:
    blizzView.loadUrl(website);
}

@Override
protected void onPostCreate(Bundle savedInstanceState)
{
    Log.i("debug_log", "onPostCreate");
    super.onPostCreate(savedInstanceState);

    // Trigger the initial hide() shortly after the activity has been
    // created, to briefly hint to the user that UI controls
    // are available.
    delayedHide(100);
}

private void toggle()
{
    if (mVisible) {
        hide();
    } else {
        show();
    }
}

private void hide()
{
    // Hide UI first
    ActionBar actionBar = getSupportActionBar();
    if (actionBar != null) {
        actionBar.hide();
    }
    mVisible = false;

    // Schedule a runnable to remove the status and navigation bar after a delay
    mHideHandler.removeCallbacks(mShowPart2Runnable);
    mHideHandler.postDelayed(mHidePart2Runnable, UI_ANIMATION_DELAY);
}

@SuppressLint("InlinedApi")

private void show()
{
    // Show the system bar
    mVisible = true;

    // Schedule a runnable to display UI elements after a delay
    mHideHandler.removeCallbacks(mHidePart2Runnable);
    mHideHandler.postDelayed(mShowPart2Runnable, UI_ANIMATION_DELAY);
}

/**
 * Schedules a call to hide() in delay milliseconds, canceling any
 * previously scheduled calls.
 */
private void delayedHide(int delayMillis)
{
    mHideHandler.removeCallbacks(mHideRunnable);
    mHideHandler.postDelayed(mHideRunnable, delayMillis);
}

public void js(WebView view, String code)
{
    String javascriptCode = "javascript:" + code;
    if (Build.VERSION.SDK_INT >= 19) {
        view.evaluateJavascript(javascriptCode, new ValueCallback<String>() {

            @Override
            public void onReceiveValue(String response) {
                Log.i("debug_log", response);
            }
        });
    } else {
        view.loadUrl(javascriptCode);
    }
}

// Event Listener ------------------------------------------------------------------------------

public void goBack(android.view.View view)
{
    blizzView.goBack();
}

// If back button of smartphone is pressed, then go back in browser history
@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
    Log.i("debug_log", "KeyDown");
    if (event.getAction() == KeyEvent.ACTION_DOWN) {
        switch (keyCode) {
            case KeyEvent.KEYCODE_BACK:
                if (blizzView.canGoBack())
                    blizzView.goBack();
                else
                    finish();
                return true;
        }
    }

    return super.onKeyDown(keyCode, event);
}

}

Option Two

Add the below block into onPageFinished method of your WebviewClient

//This will remove all javascript event listener from affected images. (offending script: MagicZoomPlus.js)
//Setback of this is that images would no longer zoom in when clicked. 

            blizzView.loadUrl(
                    "javascript:(function() { " +
                            "var slides = document.getElementsByClassName(\"MagicZoom\");\n" +
                            "for(var i = 0; i < slides.length; i++)\n" +
                            "{\n" +
                            "var old_element = slides.item(i);\n" +
                            "old_element.href = '#';\n" +
                            "                var new_element = old_element.cloneNode(true);\n" +
                            "\t\t\t\told_element.parentNode.replaceChild(new_element, old_element);\n" +
                            "       \n" +
                            "   }" +
                            "})()");


回答2:

Have you tried setting this to your webView?

 webview.setVerticalScrollBarEnabled(true);
 webview.setHorizontalScrollBarEnabled(true);


回答3:

At first remove this entire section,

@Override
        public void onPageFinished(WebView view, String url)
        {
            super.onPageFinished(view, url);

            //blizzView.Settings.setSupportZoom(true);

            blizzView.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY);

            blizzView.getSettings().setSupportZoom(true);
            blizzView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT);

            blizzView.loadUrl(
                    "javascript:(function() {"


                            //+ "jQuery('.logo').remove();" //Einige Funktionen wie z.B. alert() sind scheinbar aus Sicherheits-/Missbrauchsgründen nicht verfügbar; jQuery kann man natürlich nur nutzen wenn es eingebunden ist. Möglicherweise kann man es auch selbst einbinden.
                    + "})()"
            );

            // Hide/Show back button
            backButton = findViewById(R.id.backButton);
            backButton.setEnabled(blizzView.canGoBack());

            if (blizzView.canGoBack()) {
                backButton.setVisibility(View.VISIBLE);
            } else {
                backButton.setVisibility(View.INVISIBLE);
            }

            blizzView.setVerticalScrollBarEnabled(true);
            blizzView.setHorizontalScrollBarEnabled(true);

        }

because you can't rely on onPageFinished instead you should implement shouldOverrideUrlLoading. I'll post my complete code here.

public class TempWebActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_temp_web);

    WebView webView = findViewById(R.id.wv_scroller);
    webView.getSettings().setJavaScriptEnabled(true);

    webView.loadUrl("https://www.blizz-z.de");

    webView.setWebViewClient(new WebViewClient() {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            view.loadUrl(url);
            return true;
        }
    });
    }
}

Here's the activity layout

<?xml version="1.0" encoding="utf-8"?>
<ScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".TempWebActivity">

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

</ScrollView>

The key to achieve this is to use a ScrollView wrapper with WebView if some Javascript can intercept some touch events. Also make sure that you keep the height of WebView as wrap_content. Happy coding bro! :)



回答4:

Try to add webview in this sample..

  <NestedScrollViewHome
            android:id="@+id/scroll_nested_journey"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_below="@id/toolbar">

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

    //  add Webview here

     </LinearLayout>

        </NestedScrollViewHome>

NestedScrollViewHome.java

public class NestedScrollViewHome  extends NestedScrollView {
    @SuppressWarnings("unused")
    private int slop;
    @SuppressWarnings("unused")
    private float mInitialMotionX;
    @SuppressWarnings("unused")
    private float mInitialMotionY;
    public NestedScrollViewHome(Context context) {
        super(context);
        init(context);
    }

    private boolean enableScrolling = true;

    public boolean isEnableScrolling() {
        return enableScrolling;
    }

    public void setEnableScrolling(boolean enableScrolling) {
        this.enableScrolling = enableScrolling;
    }


    private void init(Context context) {
        ViewConfiguration config = ViewConfiguration.get(context);
        slop = config.getScaledEdgeSlop();
    }
    public NestedScrollViewHome(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }
    public NestedScrollViewHome(Context context, AttributeSet attrs,
                              int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }
    private float xDistance, yDistance, lastX, lastY;
    @SuppressWarnings("unused")
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
      if (isEnableScrolling())
      {
          final float x = ev.getX();
          final float y = ev.getY();
          switch (ev.getAction()) {
              case MotionEvent.ACTION_DOWN:
                  xDistance = yDistance = 0f;
                  lastX = ev.getX();
                  lastY = ev.getY();
                  // This is very important line that fixes
                  computeScroll();
                  break;
              case MotionEvent.ACTION_MOVE:
                  final float curX = ev.getX();
                  final float curY = ev.getY();
                  xDistance += Math.abs(curX - lastX);
                  yDistance += Math.abs(curY - lastY);
                  lastX = curX;
                  lastY = curY;
                  if (xDistance > yDistance) {
                      return false;
                  }
          }
          return super.onInterceptTouchEvent(ev);
      }else
          return false;
    }
    public interface OnScrollChangedListener {
        void onScrollChanged(NestedScrollView who, int l, int t, int oldl,
                             int oldt);
    }
    private OnScrollChangedListener mOnScrollChangedListener;
    public void setOnScrollChangedListener(OnScrollChangedListener listener) {
        mOnScrollChangedListener = listener;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if (isEnableScrolling()) {
            return super.onTouchEvent(ev);
        } else {
            return false;
        }
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        if (mOnScrollChangedListener != null) {
            mOnScrollChangedListener.onScrollChanged(this, l, t, oldl, oldt);
        }
    }
}