안 드 로 이 드 는 즉시 첫 페이지 수직 스크롤 그림 을 모방 하여 끝까지 멋 지게!

프로젝트 주소:https://github.com/JeasonWong/JikeGallery
말 이 많 지 않 으 면 먼저 효 과 를 본다.

이 효 과 는 즉시 app 에서 보 았 는데 아주 좋다 고 생각 하여 모방 한 것 이다.
먼저 제 실현 방향 을 말씀 드 리 겠 습 니 다.(위의 그림 스크롤 을 예 로 들 면 아래 의 문자 실현 효과 가 비슷 합 니 다)
사용자 정의 ViewGroup
ImageView 두 개 와 그림자 View 를 불 러 옵 니 다.
일정한 규칙 을 통 해 두 개의 ImageView 와 그들의 margin Top 을 교체 제어 하여 onLayout()에서 이 루어 집 니 다.
margin Top 의 구체 적 인 값 은 속성 애니메이션 에 의 해 제어 되 고 requestLayout()를 계속 호출 합 니 다.
이어서 차례대로 설명 하 겠 습 니 다.
사용자 정의 ViewGroup

 //    
 protected static final int STATUS_SMOOTHING = 0;
 //    
 protected static final int STATUS_STOP = 1;

 //ViewGroup  
 protected int mWidth, mHeight;
 //   marginTop 
 protected int mSmoothMarginTop;
 //    
 protected int mStatus = STATUS_STOP;
 //      
 protected int mDuration = 500;
 //    
 protected int mRepeatTimes = 0;

 ...

 @Override
 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  super.onSizeChanged(w, h, oldw, oldh);
  mWidth = w;
  mHeight = h;
  mSmoothMarginTop = -h;
  initView();
 }

 protected abstract void initView();

 ...

 /**
  *       
  *
  * @return   
  */
 protected boolean isOddCircle() {
  return mRepeatTimes % 2 == 1;
 }

먼저 다음 멤버 변 수 를 알 아 보 세 요.그 중에서 가장 중요 한 것 은 mSmoothMargin Top 입 니 다.많은 사람들 이 View 의 margin Top 을 마이너스 로 설정 할 수 있다 는 것 을 알 고 있 습 니 다.이 음 수 는 우리 에 게 너무 많은 편 의 를 가 져 다 줄 수 있 습 니 다.

위의 그림 0 은 바로 우리 가 화면 에 보 여 준 ImageView 이 고 그림 1 은 화면 밖 margin Top 이-height 인 ImageView 이다.이것 은 반드시 알 아야 다음 에 계속 실현 할 수 있다.
2.ImageView 두 개 와 그림자 View 를 불 러 옵 니 다.

 private List<String> mImgList = new ArrayList<>();
 private ImageView[] mImgs = new ImageView[2];
 private View mShadowView;

 ...

 @Override
 protected void initView() {

  //      ,         
  if (mImgList.size() == 0) {
   return;
  }

  removeAllViews();

  MarginLayoutParams params = new MarginLayoutParams(mWidth, mHeight);

  //  ImageView      
  for (int i = 0; i < mImgs.length; i++) {
   mImgs[i] = new ImageView(getContext());
   addViewInLayout(mImgs[i], -1, params, true);
   Glide.with(getContext()).load(getImgPath(i)).centerCrop().into(mImgs[i]);
  }

  //    View
  mShadowView = new View(getContext());
  mShadowView.setBackgroundColor(Color.parseColor("#60000000"));
  mShadowView.setAlpha(0);
  addViewInLayout(mShadowView, -1, params, true);
 }

 ...

 /**
  *       
  * 
  * @param position   
  * @return     
  */
 private String getImgPath(int position) {
  position = position % mImgList.size();
  return mImgList.get(position);
 } 

포인트 설명:
MarginLayoutParams 는 나중에 margin 값 을 쉽게 꺼 낼 수 있 도록 합 니 다.
addViewInLayout()requestLayout 에 대한 절대적 인 통 제 를 위해
getImgPath()순환 스크롤 을 실현 하기 위해
이렇게 되면 우리 가 필요 로 하 는 View 가 모두 만 들 어 졌 다.
3.일정한 규칙 을 통 해 두 개의 ImageView 와 그들의 margin Top 를 교체 하여 onLayout()에서 실현 합 니 다.

 @Override
 protected void onLayout(boolean changed, int l, int t, int r, int b) {

  int cCount = getChildCount();
  MarginLayoutParams cParams;

  for (int i = 0; i < cCount; i++) {
   View childView = getChildAt(i);
   cParams = (MarginLayoutParams) childView.getLayoutParams();

   int cl = 0, ct = 0, cr, cb;

   if (isOddCircle()) {
    if (i == 1) {
     cl = cParams.leftMargin;
     ct = mSmoothMarginTop + mHeight;
    } else if (i == 0) {
     cl = cParams.leftMargin;
     ct = mSmoothMarginTop;
    }
   } else {
    if (i == 0) {
     cl = cParams.leftMargin;
     ct = mSmoothMarginTop + mHeight;
    } else if (i == 1) {
     cl = cParams.leftMargin;
     ct = mSmoothMarginTop;
    }
   }
   //  shadowView
   if (i == 2) {
    cl = cParams.leftMargin;
    ct = mSmoothMarginTop + mHeight;
   }

   cr = cl + mWidth;
   cb = ct + mHeight;
   childView.layout(cl, ct, cr, cb);
  }

 }

이상 에서 실 현 된 것 은 그림 1 과 그림 2 를 계속 교체 하 는 것 이다.누가 위 에서 아래로 내 려 가 고 그림자 와 아래 의 그림 이 동기 화 되 는 것 이다.
4.margin Top 의 구체 적 인 값 은 속성 애니메이션 에 의 해 제어 되 고 requestLayout()를 계속 호출 합 니 다.
기본 뷰 그룹 먼저 보기

 /**
  *     
  *
  */
 public void startSmooth() {

  if (mStatus != STATUS_STOP) {
   return;
  }

  ValueAnimator animator = ValueAnimator.ofFloat(-mHeight, 0);
  animator.setDuration(mDuration);
  animator.setInterpolator(new AccelerateDecelerateInterpolator());
  animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
   @Override
   public void onAnimationUpdate(ValueAnimator animation) {

    float marginTop = (float) animation.getAnimatedValue();
    mSmoothMarginTop = (int) marginTop;

    if (marginTop == 0) {

     postDelayed(new Runnable() {
      @Override
      public void run() {

       mRepeatTimes++;

       mSmoothMarginTop = -mHeight;

       doAnimFinish();

       mStatus = STATUS_STOP;

      }
     }, 50);

    } else {
     doAnim();
    }
   }
  });
  animator.start();
  mStatus = STATUS_SMOOTHING;
 }

 //    
 protected abstract void doAnimFinish();

 //     
 protected abstract void doAnim();

포인트 설명:
속성 애니메이션 은 mSmoothMargin Top 이[-m Height,0]에서 변화 하 는 것 을 제어 합 니 다.
한 바퀴 를 완성 할 때마다 mRepeatTimes 가 1 증가 합 니 다.
갤러리 실현 류 를 또 보 겠 습 니 다.

 @Override
 protected void doAnimFinish() {
  if (isOddCircle()) {
   Glide.with(getContext()).load(getImgPath(mRepeatTimes + 1)).centerCrop().into(mImgs[0]);
  } else {
   Glide.with(getContext()).load(getImgPath(mRepeatTimes + 1)).centerCrop().into(mImgs[1]);
  }
  mShadowView.setAlpha(0);
 }

 @Override
 protected void doAnim() {
  mShadowView.setAlpha(((1 - (-mSmoothMarginTop) / (float) mHeight)));
  requestLayout();
 }

포인트 설명:
mSmoothMargin Top 과 mHeight 의 비율 을 통 해 그림자 View 의 투명 도 를 제어 합 니 다.
애니메이션 이 완 료 될 때마다 아래 그림(이때 아래 그림 은 화면 을 넘 어 섰 고 위 그림 은 화면 에 표 시 됨)은 세 번 째 그림 을 불 러 오고 getImgPath()를 사용 하여 꺼 내야 합 니 다.
pic1

이상 은 바로 그림 의 스크롤 실현 입 니 다.문자 의 스크롤 90%는 똑 같 습 니 다.약간 차이 가 있 는 것 은 문자 가 수직 으로 가운데 에 있어 야 한 다 는 것 입 니 다.저 는 군말 하지 않 겠 습 니 다.
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기