[Android 맞춤형 컨트롤] ScrollView 없이 위아래 두 화면 슬라이딩

  • 앞말
  • 사고방식
  • 코드
  • 사용 방법
  • 보충

  • 전언
    최근 프로젝트 원인은 상하 두 스크린이 미끄러지는 효과가 필요하다.viewpager 좌우 미끄럼이 상하 미끄럼으로 변한다고 상상할 수 있습니다.Srcollview로 실현하려고 하였으나, 버튼 충돌,listview 레이아웃 충돌 등 몇 가지 이유로, 마지막에 사용자 정의 컨트롤을 쓰기로 결정하였다.
    사고의 방향
    이전에 슬라이딩 Menu를 실현한 적이 있기 때문에 그 패턴을 참고하여 좌우 슬라이딩이 상하 슬라이딩으로 바뀌면 된다.사실은 두 개의 크기가 같은 구조로 하나는 화면에 나타나고 다른 하나는 화면 밖으로 숨어 미끄러질 때까지 기다리면 나타난다.
    코드
    내가 물려받은 건 View Group이야.다시 onLayout 방법을 다시 써서 하나의 레이아웃이 화면을 가득 채우고 다른 하나는 화면 밖에 놓는다.
    public class MySlidingMenu extends ViewGroup {
    
        private static final String TAG = MySlidingMenu.class.getName();
    
        private enum Scroll_State {
            Scroll_to_Open, Scroll_to_Close;
        }
    
        private Scroll_State state;
        private int mMostRecentY;
        private int downY;
        private boolean isOpen = false;
    
        private View menu;
        private View mainView;
    
        private Scroller mScroller;
    
        private OnSlidingMenuListener onSlidingMenuListener;
    
        public MySlidingMenu(Context context, View main, View menu) {
            super(context);
            setMainView(main);
            setMenu(menu);
            init(context);
        }
    
        private void init(Context context) {
            mScroller = new Scroller(context);
        }
    
        @Override
        protected void onLayout(boolean arg0, int l, int t, int r, int b) {
            mainView.layout(l,t,r,b);
            //         
            menu.layout(l, menu.getMeasuredHeight(), r, menu.getMeasuredHeight()*2);
        }
    
        public void setMainView(View view) {
            mainView = view;
            addView(mainView);
        }
    
        public void setMenu(View view) {
            menu = view;
            addView(menu);
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            mainView.measure(widthMeasureSpec, heightMeasureSpec);
            menu.measure(widthMeasureSpec, heightMeasureSpec);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    mMostRecentY = (int) event.getY();
                    downY = (int) event.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    int moveY = (int) event.getY();
                    int deltaY = mMostRecentY - moveY;
                    //                           Scroll  
                    if ((!isOpen && (downY - moveY) > 0)
                            || (isOpen && (downY - moveY) < 0)) {
                        scrollBy(0, deltaY);
                    }
                    mMostRecentY = moveY;
                    break;
                case MotionEvent.ACTION_UP:
                    int upY = (int) event.getY();
                    int dy = upY - downY;
                    if (!isOpen) {
                    //            menu            
                        if (dy < - menu.getMeasuredHeight() / 3) {
                            state = Scroll_State.Scroll_to_Open;
                        } else {
                            state = Scroll_State.Scroll_to_Close;
                        }
                    } else {
                    //               menu   ,        menu     ,    
                        if (dy > menu.getMeasuredHeight() / 3) {
                            state = Scroll_State.Scroll_to_Close;
                        } else {
                            state = Scroll_State.Scroll_to_Open;
                        }
                    }
                    smoothScrollto();
                    break;
                default:
                    break;
            }
            return true;
        }
    
        private void smoothScrollto() {
            int scrolly = getScrollY();
            switch (state) {
                case Scroll_to_Close:
                    mScroller.startScroll(0, scrolly, 0, - scrolly, 500);
                    isOpen = false;
                    break;
                case Scroll_to_Open:
                    mScroller.startScroll(0, scrolly, 0, menu.getMeasuredHeight()- scrolly, 500);
                    isOpen = true;
                    break;
                default:
                    break;
            }
            //        invalidate,           computeScroll  
            invalidate();
        }
    
        @Override
        public void computeScroll() {
            //    computeScrollOffset     false,   startScroll       true
            if (mScroller.computeScrollOffset()) {
                scrollTo(0, mScroller.getCurrY());
                postInvalidate();
            }
            super.computeScroll();
        }
    }

    전체 코드는 복잡한 편은 아니지만, 가장 중요한 것은 좌표의 계산이다.startScroll(int startX, int startY, int dx, int dy, int duration) 이 방법은 좌표가 미끄러지는 데 비교적 어렵다.처음에 나는 줄곧 dx,dy가 어느 방향으로 가고 마이너스가 어느 방향으로 가는지 고민했다.나중에 원본 코드를 봤어요.
    public void startScroll(int startX, int startY, int dx, int dy, int duration) {  
        mMode = SCROLL_MODE;  
        mFinished = false;  
        mDuration = duration;  
        mStartTime = AnimationUtils.currentAnimationTimeMillis();  
        mStartX = startX;  
        mStartY = startY;  //      
        mFinalX = startX + dx;  
        mFinalY = startY + dy;  //      
        mDeltaX = dx;  
        mDeltaY = dy;  
        mDurationReciprocal = 1.0f / (float) mDuration;  
        // This controls the viscous fluid effect (how much of it)  
        mViscousFluidScale = 8.0f;  
        // must be set to 1.0 (used in viscousFluid())  
        mViscousFluidNormalize = 1.0f;  
        mViscousFluidNormalize = 1.0f / viscousFluid(1.0f);  
    }  

    그래서 A(a1,a2)에서 B(b1,b2)로 미끄러지면 startScroll(a1,a2,b1-a1,b2-a2)만 있으면 된다.주로 차액을 구하다.
    사용법
        private MySlidingMenu mSlidingMenu;
        ......
        mSlidingMenu = new MySlidingMenu(this, LayoutInflater
             .from(this).inflate(R.layout.fragment1, null), LayoutInflater
             .from(this).inflate(R.layout.fragment2, null));
    

    보태다
    이것은listview 슬라이딩 충돌을 초래할 수 있습니다. 열 수가 고정되면listviewe를 다시 쓰는 onTouchEvent가false로 되돌아오는 것을 한 화면에 표시할 수 있습니다.만약 비교적 많으면, 온터치 이벤트 ()에서 getParent () 를 통과합니다.requestDisallowInterceptTouchEvent (bool) 는 어떤 컨트롤 응답 이벤트를 설정합니다.
    일반적인 사고방식은list가 머리와 꼬리를 미끄러질 때 상응하는 방향의 미끄러짐 사건을 부모 구성 요소에 전달하는 것이다.

    좋은 웹페이지 즐겨찾기