WebView加载Html片段监听滑动到底部

需求:管理端有个富文本可以添加一个阅读须知,通过接口将富文本生成的Html返回给Android端,要求展示正确展示富文本内容,并且如果内容较多时,用户需要看完所有内容(滑动到底部)才能确认进入下一步。

 简单来说需要实现加载Html片段,并且根据内容多少判断是否需要滑动到底部和是否滑动到底部了。下面封装一个自定义的WebView,实现此需求:

package com.zhn.learn_android;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.webkit.JavascriptInterface;
import android.webkit.WebChromeClient;
import android.webkit.WebView;

import java.util.concurrent.TimeUnit;

import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.Observer;
import io.reactivex.rxjava3.disposables.Disposable;

/**
 * @author : zhn
 * @date : 2022/11/1 14:04
 * description :滑动监听WebView
 */
public class ScrollListenerWebView extends WebView {

    //webView的高度,dp
    public int viewHeight = 0;
    //web内容高度,dp
    public int contentHeight = 0;

    public ScrollListenerWebView(Context context) {
        super(getFixedContext(context));
    }

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

    public ScrollListenerWebView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(getFixedContext(context), attrs, defStyleAttr);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public ScrollListenerWebView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(getFixedContext(context), attrs, defStyleAttr, defStyleRes);
    }

    /**
     * 解决Android 5.0~5.1 WebView兼容问题
     * @param context ctx
     * @return ctx
     */
    private static Context getFixedContext(Context context) {
        // Android Lollipop 5.0 & 5.1
        if (Build.VERSION.SDK_INT >= 21 && Build.VERSION.SDK_INT < 23) {
            return context.createConfigurationContext(new Configuration());
        }
        return context;
    }

    /**
     * 添加获取
     *
     * @param activity activity
     */
    public void addWebHeightSupport(Activity activity, ScrollWebListener listener) {
        this.mListener = listener;
        addWebHeightSupport(activity, this, "app");
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        viewHeight = px2dip(getContext(), getMeasuredHeight());
        Log.e("onMeasure","   viewHeight= "+viewHeight);
    }

    @JavascriptInterface
    public void contentHeight(int webContentHeight) {
        contentHeight = webContentHeight;
        if (mListener == null || contentHeight <= 0) {
            return;
        }
        Log.e("","contentHeight="+contentHeight);
        //如果html高度小于控件高度,那么说明一屏可以展示下
        if (contentHeight < viewHeight) {
            mListener.noScroll();
        } else {
            mListener.needScroll();
        }
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        if (mListener == null) {
            return;
        }
        // 当前webview的高度
        float webNow = viewHeight + px2dip(getContext(),getScrollY());
        //判断是否抵达底部
        if (webNow >= contentHeight - 10) {
            mListener.scrollBottom();
        }
    }

    /**
     * 添加内容高度支持
     *
     * @param activity        activity
     * @param jsInterface     js接口
     * @param jsInterfaceName js接口名称
     */
    @SuppressLint({"SetJavaScriptEnabled", "AddJavascriptInterface", "JavascriptInterface"})
    private void addWebHeightSupport(Activity activity, Object jsInterface, String jsInterfaceName) {
        //js支持
        getSettings().setJavaScriptEnabled(true);
        //添加JS交互方法
        this.addJavascriptInterface(jsInterface, jsInterfaceName);
        //监听加载进度
        setWebChromeClient(new WebChromeClient() {
            @Override
            public void onProgressChanged(WebView view, int newProgress) {
                super.onProgressChanged(view, newProgress);
                addWebHeightSupport(newProgress);
            }
        });
    }

    /**
     * 添加内容高度预览支持
     *
     * @param newProgress 加载进度
     */
    private void addWebHeightSupport(int newProgress) {
        if (newProgress == 100) {
            Observable.timer(200L, TimeUnit.MILLISECONDS)
                    .observeOn(AndroidSchedulers.mainThread())
                    .safeSubscribe(new Observer<Long>() {
                        @Override
                        public void onSubscribe(Disposable d) {

                        }

                        @Override
                        public void onNext(Long aLong) {
                            loadUrl("javascript:(function(){" +
                                    "var result = document.body.offsetHeight; " +
                                    "window.app.contentHeight(result);" +
                                    "})()");
                        }

                        @Override
                        public void onError(Throwable e) {

                        }

                        @Override
                        public void onComplete() {

                        }
                    });
        }
    }

    private ScrollWebListener mListener;

    public interface ScrollWebListener {

        void noScroll();

        void needScroll();

        void scrollBottom();
    }

    /**
     * 获取Html前缀
     *
     * @return
     */
    public String getHtmlPrefixStr() {
        return "<!DOCTYPE html><html><head><meta name='viewport' content='width=device-width,initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no'>" +
                "<style>" +
                "*{margin:0 !important;}" +
                "img{width:100% !important; height:auto !important; margin-top:10px !important;margin-bottom:10px !important; border-radius:4px;}" +
                "div{font-size:14px !important; color: #3A3D4B !important; font-family: PingFangSC;}" +
                "body{padding: 20px 16px 20px 20px;}" +
                "</style>" +
                "</head><body><div>";
    }

    /**
     * 获取Html后缀
     *
     * @return
     */
    public String getHtmlSuffixStr() {
        return "</div></body></html>";
    }

    /**
     * 加载Html片段
     *
     * @param htmlPart html片段
     */
    public void loadHtmlPart(String htmlPart) {
        loadDataWithBaseURL(null, getHtmlPrefixStr() + htmlPart + getHtmlSuffixStr(),
                "text/html", "utf-8", null
        );
    }

    public int px2dip(Context context, float pxValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }

}

使用:

package com.zhn.learn_android

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Button

class TestActivity : AppCompatActivity() {

    private var mWebView:ScrollListenerWebView?=null
    private var btnConfirm:Button?=null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_test)
        mWebView=findViewById(R.id.web_view)
        btnConfirm=findViewById(R.id.btn_confirm)

        mWebView!!.addWebHeightSupport(this,object : ScrollListenerWebView.ScrollWebListener{
            override fun noScroll() {
                Log.e("-TestActivity--","不需要滑动")
                btnConfirm!!.isEnabled=true
            }

            override fun needScroll() {
                Log.e("-TestActivity--","需要滑动")
                btnConfirm!!.isEnabled=false
            }

            override fun scrollBottom() {
                Log.e("-TestActivity--","滑动到底部了")
                btnConfirm!!.isEnabled=true
            }
        })
    }

    fun loadWithHtmlPart(view:View){
        var htmlPart="<p>阿神经asx酰胺北ahsx京</p>" +
                "<img src=\"https://img2.baidu.com/it/u=1245013499,1883492144&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=500\">" +
                "<p>市西安ajsbhx不熟悉asbx啊</p>" +
                "<img src=\"https://img2.baidu.com/it/u=1245013499,1883492144&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=500\">"
        mWebView!!.loadHtmlPart(htmlPart)
    }

}

效果:

device-2022-11-06-144942

总结:

1、给Html片段添加Html头和尾

2、重写onMeasure方法获取WebView控件的高度

3、通过Js交互获取html中body的高度,与WebView高度对比判断是否需要滑动

4、监听WebView的onScrollChanged方法,判断是否滑动到底部了

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值