刷新控件SwipeRefreshLayout&bug解决
来源:互联网 发布:数控火焰切割手动编程 编辑:程序博客网 时间:2024/06/08 04:10
前言:
下拉刷新在众多的App中可谓是屡见不鲜,在Version19.1之后Google将SwipeRefreshLayout添加到了support-v4包里面,是刷新控件,它只允许一个直接子类,操作上比较简单但也不免有一些坑,如滑动冲突SwipeRefreshLayout+ViewPager等等。
Part 1、SwipeRefreshLayout的基础应用
xml如:
<android.support.v4.widget.SwipeRefreshLayout android:id="@+id/srl" android:layout_width="match_parent" android:layout_height="match_parent" android:clipChildren="true"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <FrameLayout android:layout_width="match_parent" android:layout_height="200dp" android:background="#FF0000"> </FrameLayout> </LinearLayout> </android.support.v4.widget.SwipeRefreshLayout>
java中进行设置
mRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.srl); mRefreshLayout.setEnabled(true); mRefreshLayout.setDistanceToTriggerSync(300); mRefreshLayout.setProgressViewOffset(false, 200, 300); mRefreshLayout.setColorSchemeResources(R.color.swipe_color_1,R.color.swipe_color_2,R.color.swipe_color_3,R.color.swipe_color_4); mRefreshLayout.setSize(SwipeRefreshLayout.LARGE); mRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { new Handler().postDelayed(new Runnable() { @Override public void run() { mRefreshLayout.setRefreshing(false); } }, 5000); } });tips:
1、setDistanceToTriggerSync(int) // 设置手指在屏幕下拉多少距离会触发下拉刷新
2、setProgressViewOffset(boolean,int,int)//设置小圆圈的偏移量 1、是否进行缩放 2、开始出现的位置 3、最远出现的位置
3、setColorSchemeResources(int...color)//设置进度条的颜色主题 4种
4、setSize(int) //设置圆圈的大小,这里只提供了两种 DEFAULT和LARGE
5、setOnRefreshListener()//设置刷新的监听
效果~
当然你也可以在代码中将View添加在SwipeRefreshLayout里面,如:
View view = super.onCreateView(inflater, container, savedInstanceState); mRefreshLayout = new MySwipeRefreshLayout(getContext()); mRefreshLayout.addView(view, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); mRefreshLayout.setLayoutParams( new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));tips:
1、这里继承了ListFragment,生成View使用super.onCreateView()方法
2、addView方法添加ViewGroup.LayoutParams.MATCH_PARENT来确保填充fragment或者是SwipeRefreshLayout控件
Part 2、SwipeRefreshLayout进阶使用
1、实现进入Activity便进行刷新功能
代码如下:
mRefreshLayout.setRefreshing(true); new Handler().postDelayed(new Runnable() { @Override public void run() { mRefreshLayout.setRefreshing(false); } },2000);通过查看源码
public void setRefreshing(boolean refreshing) { if (refreshing && mRefreshing != refreshing) { // scale and show mRefreshing = refreshing; ... mNotify = false; startScaleUpAnimation(mRefreshListener); } else { setRefreshing(refreshing, false /* notify */); } }可以看到不管是if还是else都涉及到了mRefreshListener,查看mRefreshListener
private Animation.AnimationListener mRefreshListener = new Animation.AnimationListener() { ... @Override public void onAnimationEnd(Animation animation) { if (mRefreshing) { // Make sure the progress view is fully visible mProgress.setAlpha(MAX_ALPHA); mProgress.start(); if (mNotify) { if (mListener != null) { mListener.onRefresh(); } } mCurrentTargetOffsetTop = mCircleView.getTop(); } else { reset(); } } };由于setRefreshing(boolean)方法将mNotify置为false,所以必然不会执行到mListener.onRefresh()方法。如果想通过手动设置刷新并且触发事件则需要调用
private void setRefreshing(boolean refreshing, final boolean notify) {因为是私有的方法则通过反射调用
try { Class clazz = mRefreshLayout.getClass(); Method method = clazz.getDeclaredMethod("setRefreshing",boolean.class,boolean.class); method.setAccessible(true); method.invoke(mRefreshLayout,true,true); }catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace();2、当存在多个View引起SwipeRefreshLayout的bug
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.andly.administrator.andly_md01.swiperefleshlayout.fragment.MultiViewFragment"> <GridView android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="match_parent" android:numColumns="2" /> <TextView android:id="@android:id/empty" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="空内容" android:layout_gravity="center"/></FrameLayout>在布局文件中除了ListView或GridView之类的滑动控件外又新增了其它的控件,刚好这些控件是在滑动控件的上面则会出现如下效果
无论滑动到哪里,只要是向上滑动就会出现滑动控件
解决方案:
@Override public boolean canChildScrollUp() { }重写此方法,当滑动的时候会不停的调用此方法,只需要在这里面判断当前是否ListView或GridView的顶部即可
@Override public boolean canChildScrollUp() { if (mSwipeableChildren != null && mSwipeableChildren.length > 0) { for (View view : mSwipeableChildren) { if (view != null && view.isShown() && !canViewScrollUp(view)) { // 如果这个View显示和不能向上滑动则返回false return false; } } } return true; } private boolean canViewScrollUp(View view) { if (android.os.Build.VERSION.SDK_INT >= 14) { // 4.0以上通过canScrolVertical方法来判断 return ViewCompat.canScrollVertically(view, -1); } else { if (view instanceof AbsListView) { // 当4.0以上则通过当前可见Item的位置和第一个Item的top值来判断 final AbsListView listView = (AbsListView) view; return listView.getChildCount() > 0 && (listView.getFirstVisiblePosition() > 0 || listView.getChildAt(0).getTop() < listView.getPaddingTop()); } else { // 对于其它非滑动类型控件通过ScrollY来判断 return view.getScrollY() > 0; } } }tips:
1、SwipeRefreshLayout控件只有一个直接子控件
private void ensureTarget() { // Don't bother getting the parent height if the parent hasn't been laid // out yet. if (mTarget == null) { for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); if (!child.equals(mCircleView)) { mTarget = child; break; } } } }从源码可以看出将第一个子控件赋值给了mTarget
2、canChildScrollUp():ChildView是否可以向上滑动,如果可以则返回true(即不显示滑动进度)
Part 3、SwipeRefreshLayout冲突解决
ViewPager+SwipeRefreshLayout引起的滑动冲突,当你在SwipeRefreshLayout引入ViewPager时,会引起当你从左下右下进行滑动的时候出现刷新的效果而不是ViewPager翻页的效果
效果~
解决方案:
之所以出现如上的效果是因为触摸事件被SwipeRefreshLayout吸收了,所以ViewPager便不能处理该事件,我们只需要重新复写SwipeRefreshLayout
public boolean onInterceptTouchEvent(MotionEvent ev) {在这里面通过判断触摸偏移量来决定是否将事件交给ViewPager来处理
@Override public boolean onInterceptTouchEvent(MotionEvent ev) { switch (ev.getAction()){ case MotionEvent.ACTION_DOWN: startX = ev.getX(); startY = ev.getY(); break; case MotionEvent.ACTION_MOVE: if(isVp){//如果当前是ViewPager滑动状态则直接交给ViewPager来进行处理 return false; } float endX = ev.getX(); float endY = ev.getY(); float dx = Math.abs(endX-startX); float dy = Math.abs(endY - startY); if(dx > touchSlop && dx > dy){ isVp = true; return false; } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: isVp = false; break; } return super.onInterceptTouchEvent(ev); }
ViewPager+SwipeRefreshLayout的更多详情请看:ViewPager+SwipeRefreshLayout冲突
- 刷新控件SwipeRefreshLayout&bug解决
- 下拉刷新控件SwipeRefreshLayout
- SwipeRefreshLayout下拉刷新控件
- SwipeRefreshLayout-下拉刷新控件
- 下拉刷新控件---SwipeRefreshLayout
- 下拉刷新控件SwipeRefreshLayout
- Android SwipeRefreshLayout 刷新控件
- SwipeRefreshLayout下拉刷新与下拉控件冲突解决
- Google 下拉刷新控件SwipeRefreshLayout
- Android 下拉刷新控件 SwipeRefreshLayout
- Android 下拉刷新控件SwipeRefreshLayout
- 新下拉刷新控件:SwipeRefreshLayout
- Android 下拉刷新控件SwipeRefreshLayout
- android 控件 下拉刷新 SwipeRefreshLayout
- Android 下拉刷新控件SwipeRefreshLayout
- 下拉刷新控件SwipeRefreshLayout使用
- MaterialDesign--下拉刷新控件--SwipeRefreshLayout
- Google原生刷新控件SwipeRefreshLayout
- 给表追加主键-----报错ORA-02437: 无法验证 (customer.id) - 违反主键
- Android系统:Launcher知识点总结
- 建造者模式(Builder Pattern)的实现和示例demo
- .NET框架- 异常设计原则
- Linux(ubuntu)下tomcat的下载安装以及JavaWeb项目的部署
- 刷新控件SwipeRefreshLayout&bug解决
- html5学习笔记(二)(摘抄讲义加部分理解)
- 2017-1-12-日总结-qq国际版2012登录总报错及git清除缓存区
- Android系统预装第三方apk
- log4j配置详解
- 反卷积(Deconvolution)上采样(Upsampling)上池化(Unpooling)的区别
- QT编译安卓arm64-v8a动态库
- 已发布微信小程序汇总
- 调试进行不下去,你需要的只是你女儿的一个小玩具