自定义弹性的WebView

前言:本人菜鸟一枚,自定义控件经验不足,文章写得有不足或者错误的地方,恳请读者你指出!


一直到寻找弹性的View,也找到了很多,有满意的,有不满意的,但是有一点就是,他们写的我只会用,原理完全不懂。

像我这么“爱学习”的,要是不知道原理,心里总觉得缺少什么,于是我就在寻求那种简单明了的,原理清晰的文章,希望自己

看后也能写一篇属于自己的文章。于是才有了这篇简单的自定义弹性WebView。在这里,感谢这篇文章给我的基础与灵感。

WebView不像ScrollView那样里面有一个childView,所以自定义弹性的WebView会比自定义弹性的ScrollView简单得多。


原理:(这里只能说说我自己对这个弹性Webview的理解。不具有专业性)

一.需要有弹性效果的情景

1.当前的webview滑动到顶部,这时如果手指在屏幕上且往下Move,这时就需要webview整个布局向下滑动,手指抬起,布局弹回原来的位置,如果不能体会的,可以去用用苹果的体验一把。

2.当前的webview滑动到底部,这时如果手指在屏幕上且往上Move,这是就需要webview整个布局向上滑动,手指抬起,布局弹回原来的文职。

二.我认为的关键点:

1.如何判断webview在顶部。这个比较简单,直接通过getScrollY()==0来判断,如果为true,说明目前webView在顶部。

代码如下:

	/**
 	* 判断是否到达顶部,可以下拉
 	*
 	* @return
 	*/
	private boolean isCanPullDown() {
    		return getScrollY() == 0;
	}
 
 
	2.如何判断webView在底部呢,就是通过比较webview内容的高度与webview自身的高度+webview滑动的距离是否相等
    来判断是否到达底部。这里需要注意的是由于webView可以通过手指来放大网页,所以在获取内容的高度的时候还需要注
    意是获取当前缩放比例下的内容的高度。代码如下:
 
 
	/**
 	* 判断是不死到达底部,可以上拉
 	*
 	* @return
 	*/
	private boolean isCanPullUp() {
 
 
		//小于的时候是内容的高度小于webview的高度的时候的情况
return (( int) (getContentHeight() * getScale())) <= (getHeight() + getScrollY()); }
    三.贴源码吧,如果因为好多需要明白的我都写在注释里了,这里在bb就等于让你看两遍,浪费时间。
 
 
 
 
public class FlexiableWebView extends WebView {
    //移动因子,比如在你可以上拉或者下拉的时候,手指在屏幕上移动了200px,
    // 那么布局只移动50px,这个可以根据需求自己调整,越大,越容易拉动
    private static final float DISTANCE_SCALE = 0.25f;

    //动画执行的时间
    private static final long ANIM_TIME = 300;
    //是否能够下拉
    private boolean canPullDown = false;
    //是否能够上拉
    private boolean canPullUp = false;
    //布局是否移动过
    private boolean isMoved = false;
    //用来记录原始的布局位置信息,等下拉后者上拉后好还原成原来的位置
    private Rect rect = new Rect();
    //手指按下时的位置Y,如果手指滑动并没有移动,而是内容的滚动,则这个值实时更新为手指当前的位置Y
    private float startY = 0;
    //是不是第一次,该参数用于onlayout,因为我发现WebViewScrollView不一样,
    //WebViewonLayout方法会被连续调用,ScrollView只调用一次
    private boolean isOnce = false;

    public FlexiableWebView(Context context) {
        this(context, null);
    }

    public FlexiableWebView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

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

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        //指获取自一次的位置信息,后不在更改,这个地方在WebView中会执行多次,
        // 所以用一个boolean值来控制
        if (!isOnce) {
            rect.set(this.getLeft(), this.getTop(), this.getRight(), this.getBottom());
            isOnce = true;
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent e) {
        int action = e.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                //手指按下时初始化参数
                canPullDown = isCanPullDown();
                canPullUp = isCanPullUp();
                startY = e.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                if (!canPullUp && !canPullDown) {
                    //跟定义参数的地方一样,如果不是有布局的下拉或者下拉引起的移动,
                    // 这参数实时更新为的当前手指所在的位置
                    startY = e.getY();
                    canPullDown = isCanPullDown();
                    canPullUp = isCanPullUp();
                    //获取参数后并调试判断
                    break;
                }
                //获取此刻手指的Y,用于计算滑动的距离
                float nowY = e.getY();
                //手指在屏幕上滑动的距离
                int deltaY = (int) (nowY - startY);
                //判断是否应该移动布局
                //1.webView滑动到顶部且手指下拉
                //2.webView滑动到底部且手指上拉
                //3.webView的内容小于webview的高度
                boolean shouldMove = ((canPullDown && deltaY > 0) || (canPullUp && deltaY < 0) || (canPullUp && canPullDown));
                if (shouldMove) {
                    //利用滑动因子设置滑动的距离
                    int offset = (int) (deltaY * DISTANCE_SCALE);
                    //更新布局的位置
                    this.layout(rect.left, rect.top + offset, rect.right, rect.bottom + offset);
                    //布局已经更改
                    isMoved = true;
                }
                break;
            case MotionEvent.ACTION_UP:
                //如果布局没有更改,则跳出判断
                if (!isMoved)
                    break;
                // 开启动画
                TranslateAnimation anim = new TranslateAnimation(0, 0, this.getTop(), rect.top);
                // 设置动画时间
                anim.setDuration(ANIM_TIME);
                // view设置动画
                this.setAnimation(anim);
                // 设置回到正常的布局位置
                this.layout(rect.left, rect.top, rect.right, rect.bottom);
                // 将标志位重置
                canPullDown = false;
                canPullUp = false;
                isMoved = false;
                break;
        }
        return super.onTouchEvent(e);
    }


    /**
     * 判断是否到达顶部,可以下拉
     *
     * @return
     */
    private boolean isCanPullDown() {
        return getScrollY() == 0;
    }

    /**
     * 判断是不死到达底部,可以上拉
     *
     * @return
     */
    private boolean isCanPullUp() {
        return ((int) (getContentHeight() * getScale())) <= (getHeight() + getScrollY());
    }
}
四.使用。使用就跟原生的Webview一样的用法
 
 
	布局文件:
	
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.ljy.lambdademo.MainActivity">

    <com.ljy.lambdademo.FlexiableWebView
        android:id="@+id/wv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</RelativeLayout>
 
 
	MianActivity中的代码:
	
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    WebView wv = (WebView) findViewById(R.id.wv);
    WebSettings settings = wv.getSettings();
    settings.setJavaScriptEnabled(true);
    wv.setWebViewClient(new WebViewClient());
    wv.loadUrl("http://blog.163.com/hero_213/blog/static/3989121420115393913734/");
}
 
 
------请注意添加网络权限。
------有一个不足的地方就是在有些时候没有上拉时没有效果,如果哪位大神解决了请告诉小弟一声。
     好了,就是这样了,如果有兴趣的可以去自己新建一个项目运行了看一看效果。^_^


猜你喜欢

转载自blog.csdn.net/lljjyy001/article/details/53021354