Androidの中でViewの滑り衝突――Android開発芸術探求ノート


原文のリンクhttp://sparkyuan.me/転載は出典を明記してください.
紹介する
Androidを開発した人はいずれもこのような体得があると信じています.インターネットからダウンロードしたデモがうまく実行されていますが、スライド衝突が発生したら、Demoは正常に動作できなくなります.しかし、心配しないでください.滑りの衝突を解決するには固定モードがあります.よくあるのは内部ブロックと外部ブロックの二つがあります.このモードによってうまく解決できます.本文はViewイベントの配布に関する知識がありますので、イベントの配布についてはご参考ください.http://blog.csdn.net/l664675249/article/details/50738102
よくあるスライド衝突シーン
Android中View的滑动冲突——Android开发艺术探索笔记_第1张图片

処理規則
シーン1については、ユーザが左右にスライドすると、外部のViewブロックをクリックし、ユーザが上下にスライドすると、内部のViewブロックをクリックします.スライドが発生した場合、スライドの開始点と終点座標位置によって、垂直方向のスライド距離が大きいと垂直スライドと判断されます.そうでなければ、水平スライドと判断されます.他の二つの場合の処理方法は似ています.いずれも業務の需要から相応の規則を導き出すのです.
解決方法
外部ブロック
すべてのクリックは父の容器でブロックされます.父の容器はブロックが必要なら、必要でないなら、内部のViewに伝えます.疑似コードは以下の通りです
  public boolean onInterceptTouchEvent(MotionEvent event) {
        boolean intercepted = false;

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                intercepted = false;
                break;
            }
            case MotionEvent.ACTION_MOVE: {
                if (          ) {
                    intercepted = true;
                } else {
                    intercepted = false;
                }
                break;
            }
            case MotionEvent.ACTION_UP: {
                intercepted = false;
                break;
            }
            default:
                break;
        }
        mLastXIntercept = x;
        mLastYIntercept = y;
        return intercepted;
    }
注:ACT ION_DOWNという事件は、後続の事件をブロックすると親容器が処理するからです.
インサイド?ブロック
父の容器はいかなる事件を遮らないで、すべての事件はすべて子の元素に伝わります.サブ要素がこのイベントを必要とする場合はそのまま消耗します.親の容器に任せて処理します.この機能を完成するには、request DiscallowInterceptTouchEvent()の方法を合わせなければなりません.この方法は親容器に事件をブロックするかどうかを表します.疑似コードは以下の通りです
 public boolean dispatchTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();

        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN: {
            parent.requestDisallowInterceptTouchEvent(true);
            break;
        }
        case MotionEvent.ACTION_MOVE: {
            if (          ) {
                parent.requestDisallowInterceptTouchEvent(false);
            }
            break;
        }
        case MotionEvent.ACTION_UP: {
            break;
        }
        default:
            break;
        }
        mLastX = x;
        mLastY = y;
        return super.dispatchTouchEvent(event);
    }
注親容器はデフォルトでブロックします.ACTION_uを除きます.DOWN以外のイベントは、このようにして要素がparent.request DiscallowIntercept TouchEvent(false)を呼び出すと、親要素が必要なイベントをブロックすることができます.
締め括りをつける
  • スライド衝突を解決する方法は二つあります.外部ブロック法を勧めて、簡単に実現できます.
  • 本文ではシーン1を例に説明しました.シーン2、3のやり方は1と似ています.業務の必要に応じて処理規則を制定します.
  • 模範効果のソースコード
    Activity
    public class DemoActivity_1 extends Activity {
        private static final String TAG = "DemoActivity_1";
    
        private HorizontalScrollViewEx mListContainer;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.demo_1);
            Log.d(TAG, "onCreate");
            initView();
        }
    
        private void initView() {
            LayoutInflater inflater = getLayoutInflater();
            mListContainer = (HorizontalScrollViewEx) findViewById(R.id.container);
            final int screenWidth = MyUtils.getScreenMetrics(this).widthPixels;
            final int screenHeight = MyUtils.getScreenMetrics(this).heightPixels;
            for (int i = 0; i < 3; i++) {
                ViewGroup layout = (ViewGroup) inflater.inflate(
                        R.layout.content_layout, mListContainer, false);
                layout.getLayoutParams().width = screenWidth;
                TextView textView = (TextView) layout.findViewById(R.id.title);
                textView.setText("page " + (i + 1));
                layout.setBackgroundColor(Color.rgb(255 / (i + 1), 255 / (i + 1), 0));
                createList(layout);
                mListContainer.addView(layout);
            }
        }
    
        private void createList(ViewGroup layout) {
            ListView listView = (ListView) layout.findViewById(R.id.list);
            ArrayList datas = new ArrayList();
            for (int i = 0; i < 50; i++) {
                datas.add("name " + i);
            }
    
            ArrayAdapter adapter = new ArrayAdapter(this,
                    R.layout.content_list_item, R.id.name, datas);
            listView.setAdapter(adapter);
            listView.setOnItemClickListener(new OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView> parent, View view,
                        int position, long id) {
                    Toast.makeText(DemoActivity_1.this, "click item",
                            Toast.LENGTH_SHORT).show();
    
                }
            });
        }
    }
    水平スライドのビュー
    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 defStyle) {
            super(context, attrs, defStyle);
            init();
        }
    
        private void init() {
            mScroller = new Scroller(getContext());
            mVelocityTracker = VelocityTracker.obtain();
        }
    
        @Override
        public boolean onInterceptTouchEvent(MotionEvent event) {
            boolean intercepted = false;
            int x = (int) event.getX();
            int y = (int) event.getY();
    
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN: {
                    Log.d(TAG, "onInterceptTouchEvent: ACTION_DOWN");
                    intercepted = false;
                    if (!mScroller.isFinished()) {
                        mScroller.abortAnimation();
                        intercepted = true;
                    }
                    break;
                }
                case MotionEvent.ACTION_MOVE: {
                    Log.d(TAG, "onInterceptTouchEvent: ACTION_MOVE");
                    int deltaX = x - mLastXIntercept;
                    int deltaY = y - mLastYIntercept;
                    if (Math.abs(deltaX) > Math.abs(deltaY)) {
                        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) event.getX();
            int y = (int) event.getY();
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN: {
                    Log.d(TAG, "onTouchEvent: ACTION_DOWN");
                    if (!mScroller.isFinished()) {
                        mScroller.abortAnimation();
                    }
                    break;
                }
                case MotionEvent.ACTION_MOVE: {
                    Log.d(TAG, "onTouchEvent: ACTION_MOVE");
                    int deltaX = x - mLastX;
                    int deltaY = y - mLastY;
                    Log.d(TAG, "onTouchEvent: deltaX" + deltaX);
                    scrollBy(-deltaX, 0);
                    break;
                }
                case MotionEvent.ACTION_UP: {
    
                    int scrollX = getScrollX();
                    int scrollToChildIndex = scrollX / mChildWidth;
                    mVelocityTracker.computeCurrentVelocity(1000);
                    float xVelocity = mVelocityTracker.getXVelocity();
    
                    //                  
                    if (Math.abs(xVelocity) >= 100) {
                        mChildIndex = xVelocity > 0 ? mChildIndex - 1 : mChildIndex + 1;
                    } else {
                        //         ,      
                        mChildIndex = (scrollX + mChildWidth / 2) / mChildWidth;
                    }
                    //   0             
                    mChildIndex = Math.max(0, Math.min(mChildIndex, mChildrenSize - 1));
                    //            ,    
                    int dx = mChildIndex * mChildWidth - scrollX;
                    smoothScrollBy(dx, 0);
                    Log.d(TAG, "onTouchEvent: dx = " + dx);
                    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 widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
            int heightSpaceSize = MeasureSpec.getSize(heightMeasureSpec);
            int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
            if (childCount == 0) {
                setMeasuredDimension(0, 0);
            } else if (heightSpecMode == MeasureSpec.AT_MOST) {
                final View childView = getChildAt(0);
                measuredHeight = childView.getMeasuredHeight();
                setMeasuredDimension(widthSpaceSize, childView.getMeasuredHeight());
            } else if (widthSpecMode == MeasureSpec.AT_MOST) {
                final View childView = getChildAt(0);
                measuredWidth = childView.getMeasuredWidth() * childCount;
                setMeasuredDimension(measuredWidth, heightSpaceSize);
            } else {
                final View childView = getChildAt(0);
                measuredWidth = childView.getMeasuredWidth() * childCount;
                measuredHeight = childView.getMeasuredHeight();
                setMeasuredDimension(measuredWidth, measuredHeight);
            }
        }
    
        @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) {
            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();
        }
    }
    転載を歓迎して、転載して原文のリンクを明記して下さい.http://blog.csdn.net/l664675249/article/details/50766523