效果图:
源码地址:点击打开链接,觉得不错的请star一下,如果有bug还请指出。
自定义ViewPager用于解决滑动冲突
public class MyViewPager extends ViewPager implements OnGestureListener{ private boolean isFullScreen=true; //用于标识viewpager是否拦截事件,防止影响标签的左右滑动 private OnLayoutClickListener lc; private GestureDetector gestureDetector; private boolean canDel=true; public MyViewPager(Context context) { this(context,null); } public MyViewPager(Context context, AttributeSet attrs) { super(context, attrs); gestureDetector=new GestureDetector(context,this); this.addOnPageChangeListener(new OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { } @Override public void onPageScrollStateChanged(int state) { //防止viewpager在滚动中item仍可以上下滑动 canDel = state == SCROLL_STATE_IDLE; } }); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return !isFullScreen; } private FrameLayout frameLayout; protected float point_x, point_y; //手指按下的位置 private int left, right, bottom; private int measureWidth,measureHeight; @SuppressLint("ClickableViewAccessibility") @Override public boolean onTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { frameLayout=WebPage.webpagelist.get(getCurrentItem()).getInnerContainer(); measureWidth=frameLayout.getMeasuredWidth(); measureHeight=frameLayout.getMeasuredHeight(); point_x = ev.getRawX(); point_y = ev.getRawY(); left = frameLayout.getLeft(); right = frameLayout.getRight(); bottom = frameLayout.getBottom(); } if (ev.getAction() == MotionEvent.ACTION_MOVE){ float mov_x = ev.getRawX() - point_x; float mov_y = ev.getRawY() - point_y; Log.d("trr","mov_y"+mov_y); if(Math.abs(mov_x) < Math.abs(mov_y)&&canDel){ frameLayout.measure(MeasureSpec.makeMeasureSpec(measureWidth,MeasureSpec.AT_MOST),MeasureSpec.makeMeasureSpec(measureHeight,MeasureSpec.AT_MOST)); frameLayout.layout(left, (int) mov_y, right, bottom + (int) mov_y); } } if (ev.getAction() == MotionEvent.ACTION_UP){ Log.d("trr","frameLayout:"+frameLayout .getTop()); if(Math.abs(frameLayout.getTop())>frameLayout.getWidth()/2){ EventBus.getDefault().post(new MessageEvent(frameLayout.getTop())); }else { ObjectAnimator objectAnimator=ObjectAnimator.ofFloat(frameLayout,"translationY",frameLayout.getTop(),0); objectAnimator.setDuration(400).start(); frameLayout.measure(MeasureSpec.makeMeasureSpec(measureWidth,MeasureSpec.AT_MOST),MeasureSpec.makeMeasureSpec(measureHeight,MeasureSpec.AT_MOST)); frameLayout.layout(left,0,right,bottom); } } gestureDetector.onTouchEvent(ev); return super.onTouchEvent(ev); } public void setFullScreen(boolean fullScreen) { isFullScreen = fullScreen; } public void setOnLayoutClickListener(OnLayoutClickListener lc){ this.lc=lc; } @Override public boolean onDown(MotionEvent e) { return true; } @Override public void onShowPress(MotionEvent e) { } @Override public boolean onSingleTapUp(MotionEvent e) { lc.onLayoutClick(); //手指点击屏幕不滑动时调用 return true; } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { return false; } @Override public void onLongPress(MotionEvent e) { } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { if(Math.abs(velocityY)>7000){ EventBus.getDefault().post(new MessageEvent(frameLayout.getTop())); return true; } if(Math.abs(frameLayout.getTop())>frameLayout.getWidth()/2){ EventBus.getDefault().post(new MessageEvent(frameLayout.getTop())); }else { frameLayout.layout(left,0,right,bottom); } return true; } public interface OnLayoutClickListener{ void onLayoutClick(); } }
注意FragmentPagerAdapter和FragmentStatePagerAdapter的区别,由于要保持webview的状态,使用FragmentPagerAdapter比较好,但在删除标签页后要手动删除fragment,否则会导致内存泄露。调用notifyDataSetChanged后系统会调用destroyItem,在方法内执行fragment缓存删除。
public class WebPageAdapter extends FragmentPagerAdapter { private FragmentManager fm; public static final int ADD_PAGE=0; public static final int DELETE_PAGE=1; private int deleteItem=-1,notifyType=1; //deleteItem记录要删除的标签 public WebPageAdapter(FragmentManager fm) { super(fm); this.fm=fm; } @Override public WebViewFragment getItem(int position) { return WebPage.webpagelist.get(position); } @Override public long getItemId(int position) { return WebPage.webpagelist.get(position).hashCode(); //默认是直接返回position,会导致删除时标签页顺序错乱,所以要返回hash码 } @Override public int getItemPosition(Object object) { return POSITION_NONE; //必须返回该值调用notifyDataSetChanged才有效 } @Override public int getCount() { return WebPage.webpagelist.size(); } @Override public Object instantiateItem(ViewGroup container, int position) { return super.instantiateItem(container,position); } @Override public void destroyItem(ViewGroup container, int position, Object object) { Log.d("WebView","调用了destroyItem"); if(notifyType==1&&position==deleteItem){ fm.beginTransaction().remove((Fragment) object).commit(); //将fragment缓存移除 deleteItem=-1; return; } super.destroyItem(container, position, object); } public int getDeleteItem() { return deleteItem; } public void setDeleteItem(int deleteItem) { this.deleteItem = deleteItem; } public void notifyDataSetChanged(int type) { notifyType=type; super.notifyDataSetChanged(); } }
public class WebPage { public static List<WebViewFragment> webpagelist=new ArrayList<>(); //标签页集合 }
ViewPager配置
android:clipChildren="false" //在布局文件中viewpager的节点加上该属性设置可以在缩小viewpager时绘制两边的页面 mViewPager.setPageMargin(40); //页面间隔 mViewPager.animate().scaleX(0.65f).scaleY(0.65f).setDuration(400).start(); //缩小viewpager动画 webView.setLayerType(View.LAYER_TYPE_SOFTWARE,null); //防止webview侧滑闪屏,真机不会,模拟器仍然会
以下方法可以防止在快速滑动页面时出现错位
private void fixWebPage(int position) { try { Field field = mViewPager.getClass().getField("mCurItem"); field.setAccessible(true); field.setInt(mViewPager, position); } catch (Exception e) { e.printStackTrace(); } webpageAdapter.notifyDataSetChanged(); mViewPager.setCurrentItem(position); }
删除页面
@Subscribe(threadMode = ThreadMode.MAIN) public void onMessageEvent(MessageEvent event) { //删除动画 int viewTop = event.getViewTop(); //当手指上滑到可以删除页面时页面顶端的纵坐标 int value; if (viewTop > 0) { value = 2500; } else { value = -2500; } View selectedView = WebPage.webpagelist.get(mViewPager.getCurrentItem()).getInnerContainer(); Animation animation = new TranslateAnimation(0, 0, viewTop, value); animation.setDuration(400); animation.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { WebPage.webpagelist.remove(mViewPager.getCurrentItem()); webpageAdapter.setDeleteItem(mViewPager.getCurrentItem()); webpageAdapter.notifyDataSetChanged(WebPageAdapter.DELETE_PAGE); if (WebPage.webpagelist.size() == 0) { first = true; WebViewFragment fragment = new WebViewFragment(initWebView()); WebPage.webpagelist.add(fragment); webpageAdapter.notifyDataSetChanged(WebPageAdapter.ADD_PAGE); ZoomChange(1); } } @Override public void onAnimationRepeat(Animation animation) { } }); selectedView.startAnimation(animation); }
注:标签页的删除用到了依赖库EventBus。
文章只列出部分代码,完整源码请点击上文链接