android 继承ViewGroup实现自定义布局
2016-10-14 14:34
671 查看
直接上示例代码:
import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import android.view.ViewGroup; import android.widget.Scroller; /** * @author :huangxianfeng on 2016/10/13. * 继承ViewGroup实现自定义布局 */ public class HorizontalScrollViewEx extends ViewGroup{ private static final String TAG = "HorizontalScrollViewEx"; private int mChildrenSize; private int mChildWidth; private int mChildIndex; //分别记录上次滑动的坐标 private int mLastX = 0; private int mLastY = 0; //分别记录上次滑动的坐标(onInterceptTouchEvent) private int mLastXIntercept = 0; private int mLastYIntercept = 0; private Scroller mScroller; private VelocityTracker mVelocityTracker; public HorizontalScrollViewEx(Context context) { super(context); init(); } public HorizontalScrollViewEx(Context context, AttributeSet attrs) { super(context, attrs); init(); } public HorizontalScrollViewEx(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { if (mScroller==null){ mScroller = new Scroller(getContext()); mVelocityTracker = VelocityTracker.obtain(); } } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { boolean intercepted = false; int x = (int)ev.getX(); int y = (int)ev.getY(); switch (ev.getAction()){ case MotionEvent.ACTION_DOWN: intercepted = false; if (!mScroller.isFinished()){ mScroller.abortAnimation(); intercepted = true; } break; case MotionEvent.ACTION_MOVE: int detlaX = x-mLastXIntercept; int detlaY = y-mLastYIntercept; if (Math.abs(detlaX) > Math.abs(detlaY)){ intercepted = true; }else{ intercepted = false; } break; case MotionEvent.ACTION_UP: intercepted = false; break; default: break; } Log.d(TAG,"intercepted = "+intercepted); mLastX = x; mLastY = y; mLastXIntercept = x; mLastYIntercept = y; return intercepted; } @Override public boolean onTouchEvent(MotionEvent event) { mVelocityTracker.addMovement(event); int x = (int)getX(); int y = (int)getY(); switch (event.getAction()){ case MotionEvent.ACTION_DOWN: if (!mScroller.isFinished()){ mScroller.abortAnimation(); } break; case MotionEvent.ACTION_MOVE: int detalX = x-mLastX; int detalY = y-mLastY; scrollBy(-detalX,0); break; case MotionEvent.ACTION_UP: int scrollX = getScrollX(); mVelocityTracker.computeCurrentVelocity(1000); float xVelocity = mVelocityTracker.getXVelocity(); if (Math.abs(xVelocity) >= 50){ mChildIndex = xVelocity > 0 ? mChildIndex -1 : mChildIndex + 1; }else{ mChildIndex = (scrollX + mChildWidth / 2) / mChildWidth; } mChildIndex = Math.max(0,Math.min(mChildIndex,mChildrenSize -1 )); int dx = mChildIndex * mChildWidth - scrollX; smoothScrollBy(dx, 0); mVelocityTracker.clear(); break; default: break; } mLastX = x; mLastY = y; return true; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int measuredWidth = 0; int measuredHeight = 0; //拿到自己含有子元素的个数 final int childCount = getChildCount(); measureChildren(widthMeasureSpec,heightMeasureSpec); int widthSpaceSize = MeasureSpec.getSize(widthMeasureSpec); int widthSpaceMode = MeasureSpec.getMode(widthMeasureSpec); int heightSpaceSize = MeasureSpec.getSize(heightMeasureSpec); int heightSpaceMode = MeasureSpec.getMode(heightMeasureSpec); /** * 1.判断是否含有子元素,如果没有直接把自己的高度和宽度设置为0 * 2.判断子元素的宽度和高度是否采用的warp_content,如果采用了则把所有的子元素的宽度之和给自己并且把 * 第一个子元素的高度给自己。 * 3.再进行分别判断高度和宽度那个用了warp_content,就对其分别设置不一样的值。 */ if (childCount == 0){ setMeasuredDimension(0,0); }else if (widthSpaceMode == MeasureSpec.AT_MOST && heightSpaceMode == MeasureSpec.AT_MOST){ final View childView = getChildAt(0); measuredWidth = childView.getMeasuredWidth() * childCount; measuredHeight = childView.getMeasuredHeight(); setMeasuredDimension(measuredWidth,measuredHeight); }else if (heightSpaceMode == MeasureSpec.AT_MOST){ final View childView = getChildAt(0); measuredHeight = childView.getMeasuredHeight(); setMeasuredDimension(widthSpaceSize,childView.getMeasuredHeight()); }else if (widthSpaceMode == MeasureSpec.AT_MOST){ final View childView = getChildAt(0); measuredWidth = childView.getMeasuredWidth() * childCount; setMeasuredDimension(measuredWidth,heightSpaceSize); } /** * 以上代码有两个不规范的地方: * 1.如果没有子元素的时候,不应该直接把宽度/高度直接设置为0,而是要根据LayoutParams中的高度/宽度来做相应的处理 * 2.在测量的时候要考虑到自己和子元素的padding和margin值,这样测出来的才是最标准的 */ } /** * 完成子元素的定位: * 1.遍历所有的子元素是否处于GONE的状态,不是则放置在合适的位置 * 放置的过程也是由左向右 * 缺点:也是没有考虑到自己个子元素的padding和maigin的值 * @param changed * @param l * @param t * @param r * @param b */ @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int childLeft = 0; final int childCount = getChildCount(); mChildrenSize = childCount; for (int i = 0; i < childCount; i++) { final View childView = getChildAt(i); if (childView.getVisibility() != View.GONE){ final int childWidth = childView.getMeasuredWidth(); mChildWidth = childWidth; childView.layout(childLeft,0,childLeft + childWidth,childView.getMeasuredHeight()); childLeft += childWidth; } } } private void smoothScrollBy(int dx,int dy){ //1000ms内滑向目标位置,效果是谩慢滑动 mScroller.startScroll(getScrollX(),0,dx,0,500); invalidate(); } @Override public void computeScroll() { if (mScroller.computeScrollOffset()){ scrollTo(mScroller.getCurrX(),mScroller.getCurrY()); postInvalidate(); } } @Override protected void onDetachedFromWindow() { mVelocityTracker.recycle(); super.onDetachedFromWindow(); } }
相关文章推荐
- 在Android中,可以自定义类,继承ViewGroup等容器类,以实现自己需要的布局显示。
- android之自定义ViewGroup和自动换行的布局的实现
- android自定义viewgroup实现等分格子布局
- android之自定义ViewGroup和自动换行的布局的实现
- android之自定义ViewGroup和自动换行的布局的实现
- android自定义viewgroup实现等分格子布局
- android之自定义ViewGroup和自动换行的布局的实现
- Android自定义ViewGroup自动换行实现滑动任意布局及事件处理效果
- android之自定义ViewGroup和自动换行的布局的实现
- android之自定义ViewGroup和自动换行的布局的实现
- android自定义viewgroup实现等分格子布局
- android之自定义ViewGroup和自动换行的布局的实现
- android自定义viewgroup实现等分格子布局
- android之自定义ViewGroup和自动换行的布局的实现
- android之自定义ViewGroup和自动换行的布局的实现(支持按钮间隔)
- android之自定义ViewGroup和自动换行的布局的实现
- android之自定义ViewGroup和自动换行的布局的实现
- android自定义viewgroup实现等分格子布局
- android之自定义ViewGroup和自动换行的布局的实现
- android之自定义ViewGroup和自动换行的布局的实现