안 드 로 이 드 제작 단순 수직 상 향 하강 View 효과

12723 단어 Android상승 하강
프로필
최근 친구 회 사 는 수직 으로 떨 어 지 는 View 를 실현 해 야 합 니 다.이 View 는 처음에는 일부분 만 화면 맨 아래 에 표시 되 었 고,위 에서 당 기 는 부분 은 이 View 를 모두 끌 어 내 어 화면 에 표시 할 수 있 습 니 다.이 View 는 이 View 를 화면 아래 에 숨 길 수 있 습 니 다.
일단 최종 실현 효 과 를 살 펴 보 자.

2.사고 방향 실현
1.이 효 과 는 사실 많은 실현 방법 이 있 습 니 다.손 을 놓 을 때 viewpager 와 같은 느 린 미끄럼 효 과 를 얻 기 위해 저 는 scrollBy 로 Scroller 에 맞 추 는 것 을 선 택 했 습 니 다.편리 하면 서도 실 용적 일 것 입 니 다.
2.이 View 의 디자인 은 다음 과 같다.
(1)이 View 의 하위 view 를 layot 를 통 해 이 View 아래 에 놓 습 니 다.
(2)onTouchEvent 재 작성 방법 을 통 해 이 서브 View 에 미끄럼 효 과 를 주 고 MOVEUP 의 동작 은 이 하위 View 에 Scroller 를 추가 하여 View 의 상단 이나 아래쪽 까지 부 드 럽 게 합 니 다.
그림 참조:

실현
1.먼저 하나의 속성 을 정의 하고 서브 뷰 가 얼마나 많은 부분 을 밖으로 드 러 내야 하 는 지 를 나타 낸다.즉,위의 그림 에서 빨간색 과 녹색 이 교차 하 는 부분 이다.
res 폴 더-values 폴 더 아래 에 attrs.xml 파일 을 만 듭 니 다.
attrs.xml :

<resources>
 <declare-styleable name="MyScrollerView">
  <attr name="visibility_height" format="dimension"></attr>
 </declare-styleable>

</resources>
XML 파일 에서 이 속성 을 참조 합 니 다:

<com.zw.myfirstapp.MyScrollerView
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:layout_alignParentBottom="true"
   android:background="@android:color/transparent"
   android:id="@+id/msv"
   app:visibility_height="100dp"
   ></com.zw.myfirstapp.MyScrollerView>
코드 에서 이 속성 을 호출 합 니 다.(이 View 의 이름 은 MyScrollerView 입 니 다.제 그림 은 LinearLayout 입 니 다.ViewGroup 이나 다른 레이아웃 View 를 계승 할 수 있 습 니 다)

public MyScrollerView(Context context) {
  this(context,null);
 }

 public MyScrollerView(Context context, AttributeSet attrs) {
  this(context, attrs,0);
 }

 public MyScrollerView(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);

  TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.MyScrollerView);
  visibilityHeight = ta.getDimension(R.styleable.MyScrollerView_visibility_height,200);
  ta.recycle();

  init(context);
 }

2.onFinish Inflate 방법 을 다시 쓰 는데 이 방법 을 다시 쓰 는 이 유 는 제 가 키 View 만 있 었 으 면 좋 겠 기 때 문 입 니 다.그러면 미끄럼 의 높이 를 확정 할 수 있 습 니 다.그렇지 않 으 면 저 는 서브 View 들 의 높이 를 다시 계산 해 야 합 니 다.비교적 번 거 롭 습 니 다.이 방법 은 onMeasure 전에 호출 될 것 이다.

 @Override
 protected void onFinishInflate() {
  super.onFinishInflate();
  if(getChildCount() == 0 || getChildAt(0) == null){
   throw new RuntimeException("     !");
  }
  if(getChildCount() > 1){
   throw new RuntimeException("        !");
  }
  mChild = getChildAt(0);
 }
3.init 방법 에서 초기 화 작업 을 합 니 다.예 를 들 어 Scroller 대상 을 만 들 고 View 의 배경 을 투명 하 게 설정 합 니 다.

 private void init(Context context) {
  mScroller = new Scroller(context);
  this.setBackgroundColor(Color.TRANSPARENT);
 }
4.onMeasure 방법 과 onLayout 방법 을 다시 쓰 고 미 끄 러 질 수 있 는 최대 높이 와 하위 View 의 배열 위 치 를 확인한다(사실은 onMeasure 를 다시 쓰 지 않 아 도 된다.나 는 이렇게 쓰 는 것 이 습관 일 뿐이다).

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  mScrollHeight = (int) (mChild.getMeasuredHeight() - visibilityHeight);
 }

 @Override
 protected void onLayout(boolean changed, int l, int t, int r, int b) {
  super.onLayout(changed, l, t, r, b);
  mChild.layout(0,mScrollHeight,mChild.getMeasuredWidth(),mChild.getMeasuredHeight() + mScrollHeight);
 }

5.제 가 정의 한 멤버 변수의 의 미 를 먼저 보 세 요.

 /**
  * downY:       View     
  * moveY:           (    )
  * movedY:             (               ,            )
  */
 private int downY,moveY,movedY;

 // View
 private View mChild;

 private Scroller mScroller;

 //        
 private int mScrollHeight;

 // View     
 private boolean isTop = false;

 //   View View      
 private float visibilityHeight;

6.onTouchEvent 방법 을 다시 쓰 고 미끄럼 판단 을 하 며 설명 은 모두 주석 에 적 혀 있 습 니 다.

 @Override
 public boolean onTouchEvent(MotionEvent event) {
  switch (event.getAction()){
   case MotionEvent.ACTION_DOWN:
    //       View     
    downY = (int) event.getY();

    //   View     &&        View       ,          ,    
    if(!isTop && downY < mScrollHeight ){
     return super.onTouchEvent(event);
    }
    return true;
   case MotionEvent.ACTION_MOVE:

    moveY = (int) event.getY();
    //deY      ,    deY>0 ,    deY<0
    int deY = downY - moveY;

    //        
    if(deY > 0){
     //          ,     View     View   
     movedY += deY;
     if(movedY > mScrollHeight) movedY = mScrollHeight;

     if(movedY < mScrollHeight){
      scrollBy(0,deY);
      downY = moveY;
      return true;
     }
    }

    //        ,          View     ,              
    if(deY < 0 && isTop){
     movedY += deY;
     if(movedY < 0 ) movedY = 0;
     if(movedY > 0){
      scrollBy(0,deY);
     }
     downY = moveY;
     return true;
    }

    break;
   case MotionEvent.ACTION_UP:
    //        ,                    1/4,   View    ,         
    if(movedY > mScrollHeight / 4 && !isTop){
     mScroller.startScroll(0,getScrollY(),0,(mScrollHeight - getScrollY()));
     invalidate();
     movedY = mScrollHeight;
     isTop = true;
    }else {
     //           ,         
     mScroller.startScroll(0,getScrollY(),0, -getScrollY());
     postInvalidate();
     movedY = 0;
     isTop = false;
    }

    break;
  }
  return super.onTouchEvent(event);
 }

7.마지막 으로 coptute Scroll 방법 을 다시 써 야 합 니 다.이 방법 은 scroller 에 맞 는 것 입 니 다.

 @Override
 public void computeScroll() {
  super.computeScroll();
  if(mScroller.computeScrollOffset()){
   scrollTo(0,mScroller.getCurrY());
   postInvalidate();
  }
 }
8.scroller 의 용법 에 대해 곽 림 의 이 블 로 그 를 참고 할 수 있 습 니 다http://blog.csdn.net/guolin_blog/article/details/48719871
4.전체 코드:
xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 xmlns:app="http://schemas.android.com/apk/res-auto"
 android:id="@+id/activity_main"
 android:layout_width="match_parent"
 android:layout_height="match_parent">

  <com.zw.myfirstapp.MyScrollerView
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:layout_alignParentBottom="true"
   android:background="@android:color/transparent"
   android:id="@+id/msv"
   app:visibility_height="100dp"
   >
   <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="300dp"
    android:background="@mipmap/b"
    android:gravity="center"
    android:orientation="vertical">
    <Button
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:id="@+id/btn"
     android:text="      "/>
   </LinearLayout>

  </com.zw.myfirstapp.MyScrollerView>

</RelativeLayout>

MyScrollerView:

public class MyScrollerView extends LinearLayout {

 /**
  * downY:       View     
  * moveY:           (    )
  * movedY:             (               ,            )
  */
 private int downY,moveY,movedY;

 // View
 private View mChild;

 private Scroller mScroller;

 //        
 private int mScrollHeight;

 // View     
 private boolean isTop = false;

 //   View View      
 private float visibilityHeight;

 public MyScrollerView(Context context) {
  this(context,null);
 }

 public MyScrollerView(Context context, AttributeSet attrs) {
  this(context, attrs,0);
 }

 public MyScrollerView(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);

  TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.MyScrollerView);
  visibilityHeight = ta.getDimension(R.styleable.MyScrollerView_visibility_height,200);
  ta.recycle();

  init(context);
 }

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  mScrollHeight = (int) (mChild.getMeasuredHeight() - visibilityHeight);
 }

 @Override
 protected void onLayout(boolean changed, int l, int t, int r, int b) {
  super.onLayout(changed, l, t, r, b);
  mChild.layout(0,mScrollHeight,mChild.getMeasuredWidth(),mChild.getMeasuredHeight() + mScrollHeight);
 }

 private void init(Context context) {
  mScroller = new Scroller(context);
  this.setBackgroundColor(Color.TRANSPARENT);
 }

 @Override
 protected void onFinishInflate() {
  super.onFinishInflate();
  if(getChildCount() == 0 || getChildAt(0) == null){
   throw new RuntimeException("     !");
  }
  if(getChildCount() > 1){
   throw new RuntimeException("        !");
  }
  mChild = getChildAt(0);
 }


 @Override
 public boolean onTouchEvent(MotionEvent event) {
  switch (event.getAction()){
   case MotionEvent.ACTION_DOWN:
    //       View     
    downY = (int) event.getY();

    //   View     &&        View       ,          ,    
    if(!isTop && downY < mScrollHeight ){
     return super.onTouchEvent(event);
    }
    return true;
   case MotionEvent.ACTION_MOVE:

    moveY = (int) event.getY();
    //deY      ,    deY>0 ,    deY<0
    int deY = downY - moveY;

    //        
    if(deY > 0){
     //          ,     View     View   
     movedY += deY;
     if(movedY > mScrollHeight) movedY = mScrollHeight;

     if(movedY < mScrollHeight){
      scrollBy(0,deY);
      downY = moveY;
      return true;
     }
    }

    //        ,          View     ,              
    if(deY < 0 && isTop){
     movedY += deY;
     if(movedY < 0 ) movedY = 0;
     if(movedY > 0){
      scrollBy(0,deY);
     }
     downY = moveY;
     return true;
    }

    break;
   case MotionEvent.ACTION_UP:
    //        ,                    1/4,   View    ,         
    if(movedY > mScrollHeight / 4 && !isTop){
     mScroller.startScroll(0,getScrollY(),0,(mScrollHeight - getScrollY()));
     invalidate();
     movedY = mScrollHeight;
     isTop = true;
    }else {
     //           ,         
     mScroller.startScroll(0,getScrollY(),0, -getScrollY());
     postInvalidate();
     movedY = 0;
     isTop = false;
    }

    break;
  }
  return super.onTouchEvent(event);
 }

 @Override
 public void computeScroll() {
  super.computeScroll();
  if(mScroller.computeScrollOffset()){
   scrollTo(0,mScroller.getCurrY());
   postInvalidate();
  }
 }
}

이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기