效果图:
源码地址:点击打开链接,觉得不错的请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 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。
文章只列出部分代码,完整源码请点击上文链接