android 可上下滑动切换区域 左右滑动
来源:互联网 发布:windows 数据恢复 编辑:程序博客网 时间:2024/05/21 22:47
目前我们项目有个需求,商品详情页需要仿淘宝 而且下面的页卡可以滑动切换,于是用ViewGroup自定义了一个上下方向的ViewPager,并且需要处理各种事件传递,相信通过自定义ViewGroup我们可以实现很多不一样的页面结构需求,
github地址https://github.com/ouyangfeng/CustomerViewGroup.git
转载请注明:http://blog.csdn.net/ertingkele/article/details/49926187
以下是自定义的跟布局View源码
package com.liushengfan.test.customerviewgroup.view;import android.content.Context;import android.content.res.TypedArray;import android.support.v4.view.ViewPager;import android.util.AttributeSet;import android.view.GestureDetector;import android.view.LayoutInflater;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.widget.ListView;import android.widget.ScrollView;import android.widget.Scroller;import com.liushengfan.test.customerviewgroup.R;import java.util.ArrayList;import java.util.Collections;import java.util.Comparator;import java.util.List;/** * @author liushengfan * @see android.support.v4.view.ViewPager * <p/> * 垂直方向 ViewPager */public class ViewGroupScrollView extends ViewGroup implements ViewPager.OnPageChangeListener { private Context mContext; private View mObservedView;//正在监听的 View private ViewPager mViewPager;//底部ViewPager private View mUpView;//第一部分View private View mDownView;//第二部分View private boolean viewChang = false;//第一部分与第二部分 是否已经切换 相对于初始位置 private Scroller myScroller; private boolean isFling = false; private int boundaryY = 0; MyGestureListener gestureListener; public ViewGroupScrollView(Context context) { super(context); } public ViewGroupScrollView(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; init(); /** * 获得我们所定义的自定义样式属性 */ TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ViewGroupScrollView, 0, 0); int downViewLayoutId = a.getResourceId(R.styleable.ViewGroupScrollView_downView, 0); int upViewLayoutId = a.getResourceId(R.styleable.ViewGroupScrollView_upView, 0); mUpView = LayoutInflater.from(context).inflate(upViewLayoutId, null); mDownView = LayoutInflater.from(context).inflate(downViewLayoutId, null); a.recycle(); if (null == mUpView || null == mDownView) { throw new RuntimeException("upView or downView can not be null"); } addView(mUpView); addView(mDownView); } private void init() { myScroller = new Scroller(mContext); gestureListener = new MyGestureListener(); detector = new GestureDetector(mContext, gestureListener); } /** * 设置下部分View的资源ID * * @param layoutId */ public void setViewPagerLayoutId(int layoutId) { View v = mDownView.findViewById(layoutId); if (null == v || !(v instanceof ViewPager)) { throw new RuntimeException("can not find ViewPager in the second part of ViewGroupScrollView"); } mViewPager = (ViewPager) v; //ViewPager 设置监听器 mViewPager.addOnPageChangeListener(this); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); MeasureSpec.getSize(widthMeasureSpec); MeasureSpec.getMode(widthMeasureSpec); for (int i = 0; i < getChildCount(); i++) { View view = getChildAt(i); view.measure(widthMeasureSpec, heightMeasureSpec); } } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { View viewUp = getChildAt(0); View viewDown = getChildAt(1); boundaryY = viewUp.getMeasuredHeight(); viewUp.layout(l, t, r, boundaryY); viewDown.layout(l, boundaryY, r, b + boundaryY); if (changed) { moveToDest(); } } private GestureDetector detector; public int curIndex;// 0 top 1 bottom @Override public boolean dispatchTouchEvent(MotionEvent ev) { try { return super.dispatchTouchEvent(ev); } catch (Exception e) { e.printStackTrace(); } return false; } @Override public boolean onTouchEvent(MotionEvent event) { detector.onTouchEvent(event); switch (event.getAction()) { case MotionEvent.ACTION_UP: if (!isFling) { moveToDest(); } isFling = false; break; default: break; } return true; } /** * 两部分View自动切换 */ private void moveToDest() { int destId = (getScrollY() / (boundaryY / 2)) >= 1 ? 1 : 0; moveToDest(destId); } /** * 两部分切换 * * @param destId */ public void moveToDest(int destId) { if (0 == destId || 1 == destId) { int distance = destId * boundaryY - getScrollY(); curIndex = destId; myScroller.startScroll(getScrollX(), getScrollY(), 0, distance, Math.abs(distance / 2)); invalidate(); } } /** * 计算滚动位置 */ @Override public void computeScroll() { if (myScroller.computeScrollOffset()) { int curY = myScroller.getCurrY(); scrollTo(0, curY); invalidate(); if (0 == curY) { viewChang = false; mObservedView = mUpView; } else if (boundaryY == curY) { viewChang = true; mObservedView = getCurChild_vp(mViewPager); } } } private int startY = 0; private int startX = 0; @Override public boolean onInterceptTouchEvent(MotionEvent ev) { boolean intercept = false; switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: startY = (int) ev.getY(); startX = (int) ev.getX(); break; case MotionEvent.ACTION_UP: startX = 0; startY = 0; intercept = false; break; case MotionEvent.ACTION_MOVE: int currentY = (int) ev.getY(); int currentX = (int) ev.getX(); int distanceY = currentY - startY; int distanceX = currentX - startX; if (Math.abs(distanceY) - Math.abs(distanceX) > 5) { boolean interceptFromChildFeedback = isParentViewShouldInterceptEnvent(viewChang, mObservedView); if (viewChang) { if (interceptFromChildFeedback && distanceY > 0) { intercept = true; } else { intercept = false; } } else { if (interceptFromChildFeedback && distanceY < 0) { intercept = true; } else { intercept = false; } } } startY = currentY; startX = currentX; break; default: break; } gestureListener.setInterrupt(intercept); detector.onTouchEvent(ev); return intercept; } private class MyGestureListener extends GestureDetector.SimpleOnGestureListener { private boolean interrupt = false; @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { if (interrupt) { if (0 == getScrollY() && distanceY > 0) { scrollBy(0, (int) distanceY); } else if (getScrollY() > 0 && getScrollY() < (boundaryY)) { scrollBy(0, (int) distanceY); } else if ((boundaryY) == getScrollY() && distanceY < 0) { scrollBy(0, (int) distanceY); } } // scrollBy(0, (int) distanceY); return true; } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { isFling = true; if (velocityY > 0) { moveToDest(0); } else { moveToDest(1); } return true; } public void setInterrupt(boolean interrupt) { this.interrupt = interrupt; } } public boolean isViewChang() { return viewChang; } public void setViewChang(boolean viewChang) { this.viewChang = viewChang; } /** * 是否应该中断事件传输 * * @param viewChang 是否上下两部分布局已经切换 * @param observedView 被观察的可滚动的View * @return */ private boolean isParentViewShouldInterceptEnvent(boolean viewChang, View observedView) { boolean intercept = true; if (null == observedView) { return intercept; } if (viewChang) { if (observedView instanceof ListView) { ListView listView = (ListView) observedView; if (0 != listView.getChildCount()) { if (0 == listView.getFirstVisiblePosition() && 0 == listView.getChildAt(0).getTop()) { intercept = true; } else { intercept = false; } } else { intercept = true; } } else if (observedView instanceof ScrollView) { ScrollView scrollView = (ScrollView) observedView; if (scrollView.getScrollY() == 0) { intercept = true; } else { intercept = false; } } else { intercept = true; } } else { if (observedView instanceof ListView) { //TODO 支持ListView 判断滑动到底部 } else if (observedView instanceof ScrollView) { ScrollView scrollView = (ScrollView) observedView; View contentView = scrollView.getChildAt(0); if (contentView != null && contentView.getMeasuredHeight() <= scrollView.getScrollY() + scrollView.getHeight()) { intercept = true; } else { intercept = false; } } else { intercept = true; } } return intercept; } //ViewPager Listener begin @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { if (isViewChang()) { mObservedView = getCurChild_vp(mViewPager); } } @Override public void onPageScrollStateChanged(int state) { } //ViewPager Listener end /** * 获取ViewPager当前显示的View * * @param vp * @return */ public static View getCurChild_vp(ViewPager vp) { int childCnt = vp.getChildCount(); int totalCnt = vp.getAdapter().getCount(); int curItem = vp.getCurrentItem(); int targetIndex = 0; // 若"已加载child未达到应有值",则在边界 、或总数达不到limit if (childCnt < vp.getOffscreenPageLimit() * 2 + 1) { // 若-项数不足-加载所有至limit,直接返回当前 if (childCnt == totalCnt) targetIndex = curItem; else // 若足 { // 若在左边界(即左边child数未达到limit) if (curItem - vp.getOffscreenPageLimit() < 0) targetIndex = curItem; // 右边界 else targetIndex = vp.getOffscreenPageLimit(); } } // childCnt完整(即总项>childCnt,且不在边界) else targetIndex = vp.getOffscreenPageLimit(); // 取-子元素 List<View> vs = new ArrayList<View>(); for (int i = 0; i < childCnt; i++) vs.add(vp.getChildAt(i)); // 对子元素-排序,因默认排序-不一定正确(viewpager内部机制) Collections.sort(vs, new Comparator<View>() { @Override public int compare(View lhs, View rhs) { // TODO Auto-generated method stub if (lhs.getLeft() > rhs.getLeft()) return 1; else if (lhs.getLeft() < rhs.getLeft()) return -1; else return 0; } }); // debug // for (int i = 0; i<childCnt; i++) // System.out.println("nimei>>vp-"+i+".x:"+vs.get(i).getLeft()); // System.out.println("nimei>>index:"+targetIndex); return vs.get(targetIndex); }}
1 0
- android 可上下滑动切换区域 左右滑动
- 可左右上下滑动切换图片的界面
- android SlidingDrawer左右滑动 上下滑动
- android左右滑动监听,上下滑动
- GestureDetector学习之左右滑动,上下滑动屏幕切换页面
- Android左右滑动切换页面
- Android 页面左右滑动切换
- Android屏幕切换左右滑动
- Android屏幕切换左右滑动
- 左右上下滑动表格
- android GestureDetector简单手势检测(左右滑动、上下滑动)
- Android 自定义View 实现手势监听,左右滑动,上下滑动
- Android ListView上下滑动与item左右滑动冲突解决
- android股票联动_第一列固定其他列可左右上下滑动
- jquery上下切换滑动
- Android Activity上下滑动切换背景
- android中可左右滑动输入框
- 左右滑动与上下滑动的冲突
- tomcat源码系列(四)--关闭过程
- [leetcode 20] Valid Parentheses
- sicily 1231. The Embarrassed Cryptography
- Longest Substring Without Repeating Characters
- Servlet:项目中的各个地方的路径问题
- android 可上下滑动切换区域 左右滑动
- 我的swift第一天
- 并查集在kruskal算法中应用
- Intel x86 芯片演进路线图 2016
- GB2312简体中文编码表
- 黑马程序员--Java笔记05--继承 extends 和接口 interface
- Hibernate 映射文件属性介绍
- Replace Template and delete the tables in the drawing
- 绑定MAC的静态IP配置路由器