>  기사  >  Java  >  측면 슬라이딩 효과를 달성하기 위해 Android에서 맞춤화된 보기

측면 슬라이딩 효과를 달성하기 위해 Android에서 맞춤화된 보기

高洛峰
高洛峰원래의
2017-01-13 10:34:551147검색

렌더링:

측면 슬라이딩 효과를 달성하기 위해 Android에서 맞춤화된 보기

인터넷에는 2개의 뷰가 합쳐져 ​​있는데, 기본적으로 가로로 이동할 때는 오른쪽 뷰가 표시됩니다. 다만, QQ 최신 버전에서의 효과는 이렇지는 않지만 느낌이 매우 좋기 때문에 모방도가 높은 것을 사용하는 것이 좋습니다.

지식 포인트:

1. ViewDragHelper 사용
2. 사용자 정의된 뷰 그룹;

ViewDragHelper는 출시된 지 오래되었습니다. 익숙하지 않다면 다음과 같은 간단한 사용법을 참고하세요.


1. tryCaptureView(View child , int 포인터Id): 슬라이드할 수 있는 하위 뷰 결정

2. getViewHorizontalDragRange(View child): 내 서투른 영어로 번역하면 'returns the size of the child view that'입니다. 가로 방향으로 이동할 수 있는 단위는 픽셀입니다. 0이 반환되면 가로 방향으로 드래그할 수 없다는 의미입니다.

3. clipsViewPositionHorizontal(View child, int left, int dx) : 경계는 여기서 확인할 수 있으며 dx는 각각 다가오는 움직임을 나타냅니다.

4.onViewPositionChanged(ViewchangedView, int left, int top,

int dx, int dy): 뷰가 캡처되고 드래그 또는 설정으로 인해 위치가 변경됩니다

기본 사용법은 다음과 같습니다.

public SwipeLayout(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init();
  }
  private void init() {
    viewDragHelper = ViewDragHelper.create(this, callback);
  }
   public boolean onInterceptTouchEvent(MotionEvent ev) {
    boolean result = viewDragHelper.shouldInterceptTouchEvent(ev);
   }
   public boolean onTouchEvent(MotionEvent event) {
    viewDragHelper.processTouchEvent(event);
    return true;
  }

1) 생성자에서

2) 생성하고 onInterceptTouchEvent에서 가로채기

3) onTouchEvent에서 이벤트가 나옵니다

자, 가장 이해하기 어려운 부분이 해결되었습니다. 다음으로 구체적인 구현을 살펴보겠습니다.

먼저 레이아웃을 살펴보겠습니다.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:orientation="vertical" >
  <scrollviewgroup.lly.com.swiplayout.SwipeLayout
    android:id="@+id/swipeLayout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >
    <!-- delete区域的布局 -->
    <include layout="@layout/layout_delete" />
    <!-- item内容的布局 -->
    <include layout="@layout/layout_content" />
  </scrollviewgroup.lly.com.swiplayout.SwipeLayout>
</LinearLayout>

이에 대해 말할 것도 없습니다. 사용자 정의 뷰 그룹에는 두 개의 하위 컨트롤이 포함되어 있습니다.

그런 다음 SwipeLayout이 어떻게 구현되는지 살펴보겠습니다.

@Override
  protected void onFinishInflate() {
    super.onFinishInflate();
    deleteView = getChildAt(0);
    contentView = getChildAt(1);
  }
  @Override
  protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    deleteHeight = deleteView.getMeasuredHeight();
    deleteWidth = deleteView.getMeasuredWidth();
    contentWidth = contentView.getMeasuredWidth();
    screenWidth = getWidth();
  }
  @Override
  protected void onLayout(boolean changed, int left, int top, int right,
              int bottom) {
    // super.onLayout(changed, left, top, right, bottom);
    deleteView.layout(screenWidth - deleteWidth, 0, (screenWidth - deleteWidth)
        + deleteWidth, deleteHeight);
    contentView.layout(0, 0, contentWidth, deleteHeight);
  }

위 코드는 onlayout 내부에 중점을 두고 있습니다. 여기서는 먼저 deleteView를 그립니다. He를 오른쪽에 두고 상단에 contentView 레이어를 변경하여 표시될 때 contentView만 표시되도록 합니다.

다음으로 ontouch 방식을 살펴보겠습니다

public boolean onTouchEvent(MotionEvent event) {
    //如果当前有打开的,则下面的逻辑不能执行
    if(!SwipeLayoutManager.getInstance().isShouldSwipe(this)){
      requestDisallowInterceptTouchEvent(true);
      return true;
    }
    switch (event.getAction()) {
      case MotionEvent.ACTION_DOWN:
        downX = event.getX();
        downY = event.getY();
        break;
      case MotionEvent.ACTION_MOVE:
        //1.获取x和y方向移动的距离
        float moveX = event.getX();
        float moveY = event.getY();
        float delatX = moveX - downX;//x方向移动的距离
        float delatY = moveY - downY;//y方向移动的距离
        if(Math.abs(delatX)>Math.abs(delatY)){
          //表示移动是偏向于水平方向,那么应该SwipeLayout应该处理,请求父view不要拦截
          requestDisallowInterceptTouchEvent(true);
        }
        //更新downX,downY
        downX = moveX;
        downY = moveY;
        break;
      case MotionEvent.ACTION_UP:
        break;
    }
    viewDragHelper.processTouchEvent(event);
    return true;
  }

위 내용은 주로 이벤트 충돌을 수평으로 이동할 때 이를 가로채지 않도록 부모 뷰에 요청합니다.

다음은 핵심입니다

private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {
    @Override
    public boolean tryCaptureView(View child, int pointerId) {
      return child==contentView;
    }
    @Override
    public int getViewHorizontalDragRange(View child) {
      return deleteWidth;
    }
    @Override
    public int clampViewPositionHorizontal(View child, int left, int dx) {
      if(child==contentView){
        if(left>0)left = 0;
        if(left<-deleteWidth)left = -deleteWidth;
      }
      return left;
    }
    @Override
    public void onViewPositionChanged(View changedView, int left, int top,
                     int dx, int dy) {
      super.onViewPositionChanged(changedView, left, top, dx, dy);
      //判断开和关闭的逻辑
      if(contentView.getLeft()==0 && currentState!=SwipeState.Close){
        //说明应该将state更改为关闭
        currentState = SwipeState.Close;
        //回调接口关闭的方法
        if(listener!=null){
          listener.onClose(getTag());
        }
        //说明当前的SwipeLayout已经关闭,需要让Manager清空一下
        SwipeLayoutManager.getInstance().clearCurrentLayout();
      }else if (contentView.getLeft()==-deleteWidth && currentState!=SwipeState.Open) {
        //说明应该将state更改为开
        currentState = SwipeState.Open;
        //回调接口打开的方法
        if(listener!=null){
          listener.onOpen(getTag());
        }
        //当前的Swipelayout已经打开,需要让Manager记录一下下
        SwipeLayoutManager.getInstance().setSwipeLayout(SwipeLayout.this);
      }
    }
    @Override
    public void onViewReleased(View releasedChild, float xvel, float yvel) {
      super.onViewReleased(releasedChild, xvel, yvel);
      if(contentView.getLeft()<-deleteWidth/2){
        //应该打开
        open();
      }else {
        //应该关闭
        close();
      }
    }
  };

처음에 위 코드에서 메서드를 모두 언급했습니다. tryCaptureView에서 contentView를 슬라이드하도록 허용합니다. getViewHorizontalDragRange Zhongquedong의 슬라이딩 범위는 CLAMPViewPositionHorizontal에서 제한됩니다. 상태는 onViewPositionChanged에서 업데이트됩니다. 마지막으로 손가락을 떼면 뷰가 자동으로 롤백됩니다.

/**
  * 打开的方法
  */
 public void open() {
   viewDragHelper.smoothSlideViewTo(contentView,-deleteWidth,contentView.getTop());
   ViewCompat.postInvalidateOnAnimation(SwipeLayout.this);
 }
 /**
  * 关闭的方法
  */
 public void close() {
   viewDragHelper.smoothSlideViewTo(contentView,0,contentView.getTop());
   ViewCompat.postInvalidateOnAnimation(SwipeLayout.this);
 };
 public void computeScroll() {
   if(viewDragHelper.continueSettling(true)){
     ViewCompat.postInvalidateOnAnimation(this);
   }
 }

ComputeScroll 메서드를 다시 작성하세요. 그렇지 않으면 슬라이딩 효과가 더 이상 움직이지 않습니다.

이제 사용자 정의 프레임 레이아웃이 완성되었습니다

하지만 슬라이드 아웃된 뷰에서 위아래로 슬라이드할 때 이 뷰의 deleteView가 계속 표시되므로 문제를 발견했습니다. 여전히 액티비티에 추가해야 합니다. 처리해 보겠습니다.

recyView.setOnScrollListener(new RecyclerView.OnScrollListener() {
     @Override
     public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
       super.onScrollStateChanged(recyclerView, newState);
     }
     @Override
     public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
       super.onScrolled(recyclerView, dx, dy);
       if(dy>0 || dy<0){
         SwipeLayoutManager.getInstance().closeCurrentLayout();
       }
     }
   });

이 RecyclerView가 위아래로 슬라이드되면 하위 뷰를 재설정하세요.

하루만 기다리세요.

ps: 원래는 eclipse에서 listview로 구현했지만 Google이 더 이상 eclipse를 지원하지 않는다는 점과 listview가 RecyclerView로 대체될 예정이라는 점을 고려하여 결국 Android studio로 전환하여 RecyclerView 세트로 구현했습니다. .

위는 사이드 슬라이딩 효과를 구현하기 위해 에디터가 도입한 Android의 커스텀 뷰입니다. 궁금한 사항이 있으면 메시지를 남겨주시면 에디터가 답변해 드리겠습니다. 시간에 당신에게. 또한 PHP 중국어 웹사이트를 지원해 주신 모든 분들께 감사드립니다!

사이드 슬라이딩 효과를 얻기 위해 Android에서 뷰를 사용자 정의하는 것과 관련된 더 많은 기사를 보려면 PHP 중국어 웹사이트에 주목하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.