自定义弹性的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中,因为我发现WebView是ScrollView不一样,
//WebView的onLayout方法会被连续调用,而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/");
}------请注意添加网络权限。
------有一个不足的地方就是在有些时候没有上拉时没有效果,如果哪位大神解决了请告诉小弟一声。
好了,就是这样了,如果有兴趣的可以去自己新建一个项目运行了看一看效果。^_^
声明:该文观点仅代表作者本人,入门客AI创业平台信息发布平台仅提供信息存储空间服务,如有疑问请联系rumenke@qq.com。
- 上一篇:没有了
- 下一篇:没有了
