美文网首页安卓开发
模仿UC浏览半屏显示push消息过来的网页

模仿UC浏览半屏显示push消息过来的网页

作者: 蓝不蓝编程 | 来源:发表于2021-11-06 09:59 被阅读0次

背景

不少浏览器在显示push消息时,采用半屏显示,顶部会露出一截,同时页面支持上下滑动,下滑还可以关闭页面。
下面是UC浏览器的效果:


UC浏览器效果

我实现的效果

实现效果

实现方案

方案一:继承FrameLayout,覆写事件处理方法,然后把WebView当做子View放到里面。
方案二:继承WebView,覆写事件处理方法。

方案一代码

class WebViewDragLayout : FrameLayout {

    private var downY: Float = 0f
    private var hasTouched = false
    private var mHidePageListener: HidePageListener? = null
    private val goUpAnimTime = 200L
    private val goDownAnimTime = 200L
    private val originalPaddingTop = 300
    private var mWebView: WebView? = null
    private lateinit var mToCloseLayout: View

    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)

    fun setHidePageListener(hidePageListener: HidePageListener) {
        mHidePageListener = hidePageListener
    }

    fun setChildViews(webView: WebView, toCloseLayout: View) {
        mWebView = webView
        mToCloseLayout = toCloseLayout
    }

    private fun shouldIntercept(): Boolean {
        return true
    }

    override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
        if (!shouldIntercept()) {
            return false
        }
        if (isTouchOnCloseLayout(event)) {
            return false
        }

        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                downY = event.rawY
                return !hasTouched
            }
            MotionEvent.ACTION_MOVE -> {
                var newPadding = (event.rawY - downY).toInt()
                if (!hasTouched) {
                    newPadding += originalPaddingTop
                }
                if (newPadding <= 0) {
                    newPadding = 0
                }

                return !hasTouched || (isMovingDown(newPadding) && isWebViewReachedTop())
            }
        }
        return false
    }

    /**
     * 判断是否点击在toCloseLayout上
     */
    private fun isTouchOnCloseLayout(event: MotionEvent) =
        event.y >= mToCloseLayout.y && event.y <= mToCloseLayout.y + mToCloseLayout.height

    private fun isMovingDown(newPadding: Int) = newPadding > 0

    private fun isWebViewReachedTop() = mWebView?.scrollY == 0

    override fun onTouchEvent(event: MotionEvent): Boolean {
        var newPadding: Int
        if (event.action == MotionEvent.ACTION_DOWN) {
            downY = event.rawY
        } else if (event.action == MotionEvent.ACTION_MOVE) {

            var yOffset = (event.rawY - downY).toInt()
            newPadding = yOffset
            if (!hasTouched) {
                newPadding += originalPaddingTop
            }
            if (newPadding <= 0) {
                newPadding = 0
            }
            updateTopPadding(newPadding)
        } else if (event.action == MotionEvent.ACTION_UP) {
            hasTouched = true
            val yOffset = event.rawY - downY
            if (yOffset > height / 4) {
                hidePageWithAnim()
            } else {
                movePageToTopWithAnim()
            }
        }
        return true
    }

    private fun movePageToTopWithAnim() {
        val anim = ObjectAnimator.ofInt(paddingTop, 0)
        anim.duration = goUpAnimTime
        anim.addUpdateListener { valueAnimator ->
            updateTopPadding(
                valueAnimator.animatedValue.toString().toInt()
            )
        }
        anim.start()
    }

    private fun updateTopPadding(paddingValue: Int) {
        setPadding(0, paddingValue, 0, 0)
    }

    fun hidePageWithAnim() {
        val anim = ObjectAnimator.ofInt(paddingTop, height)
        anim.duration = goDownAnimTime
        anim.addUpdateListener { valueAnimator ->
            updateTopPadding(
                valueAnimator.animatedValue.toString().toInt()
            )
        }
        anim.addListener(object : Animator.AnimatorListener {
            override fun onAnimationEnd(p0: Animator?) {
                mHidePageListener?.onHide()
                visibility = GONE
            }

            override fun onAnimationStart(p0: Animator?) {}
            override fun onAnimationCancel(p0: Animator?) {}
            override fun onAnimationRepeat(p0: Animator?) {}
        })
        anim.start()
    }
}

interface HidePageListener {
    fun onHide()
}

使用方法:

  • 布局文件:activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FF0">

    <cn.hsp.halfscreenwebview.WebViewDragLayout
        android:id="@+id/webViewDragLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingTop="100dp">

        <WebView
            android:id="@+id/webView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginTop="40dp" />

        <LinearLayout
            android:id="@+id/toCloseLayout"
            android:layout_width="match_parent"
            android:layout_height="40dp">

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="40dp"
                android:background="#FFF"
                android:src="@drawable/ic_down" />
        </LinearLayout>

    </cn.hsp.halfscreenwebview.WebViewDragLayout>

</FrameLayout>
  • activity代码代码:
package cn.hsp.halfscreenwebview

import android.os.Build
import android.os.Bundle
import android.webkit.WebSettings
import android.webkit.WebView
import androidx.appcompat.app.AppCompatActivity
import cn.hsp.halfscreenwebview.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        val url = "https://www.baidu.com"

        binding.apply {
            setSettings(webView)
            webView.loadUrl(url)
            webViewDragLayout.setChildViews(webView, toCloseLayout)
        }
    }

    private fun setSettings(webView: WebView) {
        val settings = webView.settings
        settings.javaScriptEnabled = true//设置WebView属性,能够执行Javascript脚本
        settings.cacheMode = WebSettings.LOAD_NO_CACHE
        settings.layoutAlgorithm = WebSettings.LayoutAlgorithm.NORMAL
        settings.allowFileAccess = true //设置可以访问文件
        settings.builtInZoomControls = false //设置支持缩放
        settings.setSupportZoom(true)
        settings.useWideViewPort = true
        settings.loadWithOverviewMode = true
        settings.setAppCacheEnabled(true)
        settings.domStorageEnabled = true
        settings.databaseEnabled = true
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
        }
    }
}
  • drawable资源:ic_down.xml
<vector android:height="24dp" android:tint="#6A6A6A"
    android:viewportHeight="24" android:viewportWidth="24"
    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
    <path android:fillColor="@android:color/white" android:pathData="M7.41,8.59L12,13.17l4.59,-4.58L18,10l-6,6 -6,-6 1.41,-1.41z"/>
</vector>

方案二代码

class DragWebView : WebView {

    private var downY: Float = 0f
    private var hasTouched = false
    private var mHidePageListener: HidePageListener? = null
    private val goUpAnimTime = 200L
    private val goDownAnimTime = 200L
    private val originalPaddingTop = 300

    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {}

    fun setHidePageListener(hidePageListener: HidePageListener) {
        mHidePageListener = hidePageListener
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        val parentView = parent as ViewGroup

        var newPadding: Int
        if (event.action == MotionEvent.ACTION_DOWN) {
            downY = event.rawY
            if (hasTouched) {
                return super.onTouchEvent(event)
            }
        } else if (event.action == MotionEvent.ACTION_MOVE) {
            var yOffset = (event.rawY - downY).toInt()
            newPadding = yOffset
            if (!hasTouched) {
                newPadding += originalPaddingTop
            }
            if (newPadding <= 0) {
                newPadding = 0
            }
            if (hasTouched) {
                if (newPadding > 0 && scrollY <= 0) {
                    updateTopPadding(parentView, newPadding)
                }
                return super.onTouchEvent(event)
            } else {
                updateTopPadding(parentView, newPadding)
            }
        } else if (event.action == MotionEvent.ACTION_UP) {
            hasTouched = true
            val yOffset = event.rawY - downY
            if (yOffset > parentView.height / 4) {
                hidePageWithAnim(parentView)
            } else {
                movePageToTopWithAnim(parentView)
            }
            return super.onTouchEvent(event)

        } else if (event.action == MotionEvent.ACTION_CANCEL) {
            return super.onTouchEvent(event)
        }
        return true
    }

    private fun movePageToTopWithAnim(parentView: ViewGroup) {
        val anim = ObjectAnimator.ofInt(parentView.paddingTop, 0)
        anim.duration = goUpAnimTime
        anim.addUpdateListener { valueAnimator -> updateTopPadding(parentView, valueAnimator.animatedValue.toString().toInt()) }
        anim.start()
    }

    private fun updateTopPadding(parentView: ViewGroup, paddingValue: Int) {
        parentView.setPadding(0, paddingValue, 0, 0)
    }

    private fun hidePageWithAnim(parentView: ViewGroup) {

        val anim = ObjectAnimator.ofInt(parentView.paddingTop, parentView.height)
        anim.duration = goDownAnimTime
        anim.addUpdateListener { valueAnimator -> updateTopPadding(parentView, valueAnimator.animatedValue.toString().toInt()) }
        anim.addListener(object : Animator.AnimatorListener {
            override fun onAnimationEnd(p0: Animator?) {
                mHidePageListener?.onHide()
            }

            override fun onAnimationStart(p0: Animator?) {}
            override fun onAnimationCancel(p0: Animator?) {}
            override fun onAnimationRepeat(p0: Animator?) {}
        })
        anim.start()
    }
}

interface HidePageListener {
    fun onHide()
}

使用方法:

  • 布局文件:activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FF0">

    <FrameLayout
        android:id="@+id/topLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingTop="100dp">

        <cn.hsp.demo.MyWebView
            android:id="@+id/webView"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

        <ImageView
            android:id="@+id/imageView"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:background="#FFF"
            android:src="@drawable/ic_down" />
    </FrameLayout>
</FrameLayout>
  • activity代码代码:
class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        val url = "https://www.baidu.com"

        binding.apply {
            setSettings(webView)
            webView.loadUrl(url)
            imageView.setOnClickListener {
                hidePageWithAnim(topLayout)
            }
        }
    }

    private fun hidePageWithAnim(parentView: ViewGroup) {
        val anim = ObjectAnimator.ofFloat(
            parentView,
            "translationY",
            parentView.translationY,
            parentView.height.toFloat()
        )
        anim.duration = 200
        anim.addListener(object : Animator.AnimatorListener {
            override fun onAnimationEnd(p0: Animator?) {
                Log.i("MainActivity", "closed")
            }

            override fun onAnimationStart(p0: Animator?) {}
            override fun onAnimationCancel(p0: Animator?) {}
            override fun onAnimationRepeat(p0: Animator?) {}
        })
        anim.start()
    }

    private fun setSettings(webView: DragWebView) {
        val settings = webView.settings
        settings.javaScriptEnabled = true//设置WebView属性,能够执行Javascript脚本
        settings.cacheMode = WebSettings.LOAD_NO_CACHE
        settings.layoutAlgorithm = WebSettings.LayoutAlgorithm.NORMAL
        settings.allowFileAccess = true //设置可以访问文件
        settings.builtInZoomControls = false //设置支持缩放
        settings.setSupportZoom(true)
        settings.useWideViewPort = true
        settings.loadWithOverviewMode = true
        settings.setAppCacheEnabled(true)
        settings.domStorageEnabled = true
        settings.databaseEnabled = true
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
        }
    }
}
  • drawable资源:ic_down.xml
<vector android:height="24dp" android:tint="#6A6A6A"
    android:viewportHeight="24" android:viewportWidth="24"
    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
    <path android:fillColor="@android:color/white" android:pathData="M7.41,8.59L12,13.17l4.59,-4.58L18,10l-6,6 -6,-6 1.41,-1.41z"/>
</vector>

完整源代码

https://gitee.com/hspbc/halfScreenWebView

零基础系列

《零基础学安卓编程》
《零基础学Java编程》
《零基础学鸿蒙编程》

关于我

厦门大学计算机专业 | 前华为工程师
专注《零基础学编程系列》,包含:Java | 安卓 | 前端 | Flutter | 小程序 | 鸿蒙
全网可关注:花生皮编程

相关文章

  • 模仿UC浏览半屏显示push消息过来的网页

    背景 不少浏览器在显示push消息时,采用半屏显示,顶部会露出一截,同时页面支持上下滑动,下滑还可以关闭页面。下面...

  • 解决手机UC浏览器图片不显示问题

    解决手机UC浏览器图片不显示问题 在其他手机浏览器没问题,但是到了UC浏览器就有问题了,经过逐步排查,发现UC浏览...

  • 第三天:让简历有点色彩

    将网页在浏览器中一屏显示,不出现滚动条 body{width:100%;height:100%;overflow:...

  • 利用C++制作仿IE网页浏览器!

    网页浏览器(web browser)是一种互联网文字、影像及其他资讯查询工具。网页浏览器包含360安全浏览器、UC...

  • UC 浏览器曝中间人攻击漏洞,官方:已修复,国内版不受影响

    最新消息UC 官方已回复,声明中称:“海外媒体报道 UC 浏览器国际版的潜在漏洞,已在第一时间得到修复。UC 浏览...

  • H5页面自动适应横竖屏

    对于样式: 通过html标签可强制移动端浏览器横屏或竖屏但兼容性较差,目前仅有: UC强制竖屏: QQ强制竖屏: ...

  • HTML学习

    1.HTML 文档 = 网页 Web 浏览器的作用是读取 HTML 文档,并以网页的形式显示出它们。浏览器不会显示...

  • windows快捷键

    Ctrl+W关闭当前浏览网页 Ctrl+Shift+T恢复之前关闭了的浏览网页 Windows+L锁屏 Windo...

  • 2018-10-26 -HTTP状态码

    HTTP状态码 当浏览者访问一个网页时,浏览者的浏览器会向网页所在服务器发出请求。当浏览器接收并显示网页前,此网页...

  • HTTP状态码及分类

    HTTP状态码 当浏览者访问一个网页时,浏览者的浏览器会向网页所在服务器发出请求。当浏览器接收并显示网页前,此网页...

网友评论

    本文标题:模仿UC浏览半屏显示push消息过来的网页

    本文链接:https://www.haomeiwen.com/subject/djtwaltx.html