自定义弹性的WebView

来源:互联网 发布:logo设计软件免费 编辑:程序博客网 时间:2024/06/05 19:43

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


一直到寻找弹性的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中的代码:
@Overrideprotected 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/");}
------请注意添加网络权限。
------有一个不足的地方就是在有些时候没有上拉时没有效果,如果哪位大神解决了请告诉小弟一声。
     好了,就是这样了,如果有兴趣的可以去自己新建一个项目运行了看一看效果。^_^


1 0