5

내 앱에서 iOS와 유사한 반송 초과 효과를 구현하고 싶습니다.iOS는 Android의 스크롤 오버 효과를 좋아합니다.

나는이 link을 우연히 발견하여 사용자 정의 ScrollView을 생성합니다. 그러나 문제는 내가 위아래로 빠르게 스크롤 할 때 제대로 작동하지만 화면 맨 아래 나 맨 위를 당기면 막 붙어 효과가 더 이상 작동하지 않는다는 것입니다. 애니메이션의 종류의 예로서

난 당신이 볼 수 달성하고자 :

public class ObservableScrollView extends ScrollView 
{ 
    private static final int MAX_Y_OVERSCROLL_DISTANCE = 150; 

    private Context mContext; 
    private int mMaxYOverscrollDistance; 

    public ObservableScrollView(Context context) 
    { 
     super(context); 
     mContext = context; 
     initBounceScrollView(); 
    } 

    public ObservableScrollView(Context context, AttributeSet attrs) 
    { 
     super(context, attrs); 
     mContext = context; 
     initBounceScrollView(); 
    } 

    public ObservableScrollView(Context context, AttributeSet attrs, int defStyle) 
    { 
     super(context, attrs, defStyle); 
     mContext = context; 
     initBounceScrollView(); 
    } 

    private void initBounceScrollView() 
    { 
     //get the density of the screen and do some maths with it on the max overscroll distance 
     //variable so that you get similar behaviors no matter what the screen size 

     final DisplayMetrics metrics = mContext.getResources().getDisplayMetrics(); 
     final float density = metrics.density; 

     mMaxYOverscrollDistance = (int) (density * MAX_Y_OVERSCROLL_DISTANCE); 
    } 

    @Override 
    protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) 
    { 
     //This is where the magic happens, we have replaced the incoming maxOverScrollY with our own custom variable mMaxYOverscrollDistance; 
     return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, mMaxYOverscrollDistance, isTouchEvent); 
    } 
} 

답변

13

내가 빨리 넣어 가지고 :

이 내가 현재 가지고있는 코드입니다 CoordinatorLayout.Behavior을 기반으로하는 간단한 솔루션을 함께 제공합니다. 완벽하지는 않습니다. 약간 시간을 미세하게 조정할 수 있지만 나쁘지는 않습니다. 어쨌든 결과는 다음과 같이 보일 것이다 :

enter image description here

을 작은 쪽 참고로 내가 대답으로 시작하기 전에 : 난 강력하게 대신 일반 ScrollView의 지원 라이브러리에서 NestedScrollView를 사용하는 것이 좋습니다. 이들은 어떤 식 으로든 동일하지만, NestedScrollView은 더 낮은 API 레벨에서 정확한 중첩 된 스크롤 동작을 구현합니다.

어쨌든의 내 대답과 함께 시작하자 : 내가 생각 해낸 해결책은 어떤 스크롤 컨테이너 일하는 것이 될 그것을 ScrollView, ListView 또는 RecyclerView 당신이 그것을 구현하기 위해 어떤 Views를 서브 클래 싱 할 필요가 없습니다. 당신이 이미 그것을 사용하지 않는 경우

먼저 당신은 당신의 프로젝트에 구글의 디자인 지원 라이브러리를 추가해야합니다

compile 'com.android.support:design:25.0.1' 

가 기억하는 당신은 방법으로 (API 레벨 25를하는 당신이해야 목표로하지 않는 경우) API 레벨의 최신 버전을 포함해야합니다 (예 : API 레벨 24의 경우 compile 'com.android.support:design:24.2.0').

사용중인 스크롤 가능한 컨테이너는 레이아웃에서 CoordinatorLayout으로 묶어야합니다. 내 예제에서 나는 NestedScrollView 사용하고 있습니다 :

<?xml version="1.0" encoding="utf-8"?> 
<android.support.design.widget.CoordinatorLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 

    <android.support.v4.widget.NestedScrollView 
     android:layout_width="match_parent" 
     android:layout_height="match_parent"> 

     <!-- content --> 

    </android.support.v4.widget.NestedScrollView> 

</android.support.design.widget.CoordinatorLayout> 

CoordinatorLayout는 직접적인 자식 뷰에 Behavior을 할당 할 수 있습니다. 이 경우 overscroll bounce 효과를 구현할 을 NestedScrollView에 할당 할 예정입니다. 난 그냥 빨리 무엇을 위의 설명 하겠어 있도록 Behavior가 무엇인지 설명하면서

public class OverScrollBounceBehavior extends CoordinatorLayout.Behavior<View> { 

    private int mOverScrollY; 

    public OverScrollBounceBehavior() { 
    } 

    public OverScrollBounceBehavior(Context context, AttributeSet attrs) { 
     super(context, attrs); 
    } 

    @Override 
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) { 
     mOverScrollY = 0; 
     return true; 
    } 

    @Override 
    public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) { 
     if (dyUnconsumed == 0) { 
      return; 
     } 

     mOverScrollY -= dyUnconsumed; 
     final ViewGroup group = (ViewGroup) target; 
     final int count = group.getChildCount(); 
     for (int i = 0; i < count; i++) { 
      final View view = group.getChildAt(i); 
      view.setTranslationY(mOverScrollY); 
     } 
    } 

    @Override 
    public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target) { 
     final ViewGroup group = (ViewGroup) target; 
     final int count = group.getChildCount(); 
     for (int i = 0; i < count; i++) { 
      final View view = group.getChildAt(i); 
      ViewCompat.animate(view).translationY(0).start(); 
     } 
    } 
} 

및 작동 방법은이 답변의 범위를 벗어납니다 :

것은의 그냥 Behavior의 코드를 살펴 보자 코드 않습니다. BehaviorCoordinatorLayout의 직접 하위에서 발생하는 모든 스크롤 이벤트를 차단합니다. onStartNestedScroll() 메서드에서 우리는 스크롤 이벤트에 관심이 있기 때문에 true을 반환합니다.onNestedScroll()에서 우리는 스크롤 컨테이너 (즉, overscroll)에 의해 소비되지 않은 수직 스크롤의 양을 표시 한 다음 그 양만큼 스크롤 컨테이너의 자식을 변환하는 것을 알려주는 dyUnconsumed 매개 변수를 봅니다. 델타 값을 얻는 중이므로 mOverscrollY 변수에서 모든 값을 합산해야합니다. onStopNestedScroll()은 스크롤링 이벤트가 중지 될 때 호출됩니다. 이것은 스크롤링 컨테이너의 모든 자식을 원래 위치로 다시 애니메이션 할 때입니다.

우리가 layout_behavior XML 속성을 사용하고 우리가 사용하고자하는 Behavior의 전체 클래스 이름을 전달하는 데 필요한 NestedScrollViewBehavior를 할당합니다. 내 예제에서는 위의 클래스는 패키지 com.github.wrdlbrnft.testapp에 있으므로 값으로 com.github.wrdlbrnft.testapp.OverScrollBounceBehavior을 설정해야합니다.

<?xml version="1.0" encoding="utf-8"?> 
<android.support.design.widget.CoordinatorLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 

    <android.support.v4.widget.NestedScrollView 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     app:layout_behavior="com.github.wrdlbrnft.testapp.OverScrollBounceBehavior"> 

     <!-- content --> 

    </android.support.v4.widget.NestedScrollView> 

</android.support.design.widget.CoordinatorLayout> 

공지 사항 나는 CoordinatorLayout에 추가 된 네임 스페이스와 나는 NestedScrollView에 추가 app:layout_behavior 속성 : layout_behaviorCoordinatorLayout 그래서 우리는 올바른 네임 스페이스를 접두사하는 데 필요한의 사용자 지정 속성입니다.

그리고 그게 전부입니다! 이 대답이 내가 의도 한 것보다 길게 밝혀지기는했지만 CoordinatorLayoutBehaviors을 기초로 몇 가지 기본 사항을 건너 뛰었습니다. 그래서 만약 당신이 이것들에 익숙하지 않거나 다른 질문이 있으면 언제든지 물어보십시오.

+0

안녕 @Xaver 캐 플러 감사합니다. 그리고 또 하나 의심의 여지가 있습니다. 우리는 수동으로 튀어 오르기 위해 수동으로 끌어 당깁니다. 그러나 붙어 있던 스크린 gif에서, 우리가 스크롤하고 바닥에 도달하면 다시 튀어 오릅니다. 상단에서도 마찬가지입니다 .i 앱을 다운로드하여 확인했습니다. 그것은 scrollview에서 어떻게 달성 될 수 있습니까? – Star

+0

@Star 나는 당신이하는 말을 이해하지 못합니다. 내 대답에는 이미 답변에 gif를 복제하는 솔루션이 포함되어 있습니다. 그 밖에 무엇을 원하십니까? –

+0

@Shadow가 맞는지 확인하십시오. 초과 스크롤을 기하 급수적으로 고정하는 데 필요한 것은 동일한 수학입니다. –

0

사용하여 업데이트에 대한이

Private ScrollView scrMain; 

scrMain = (ScrollView) v.findViewbyId(R.id.scrMain); 

OverScrollDecorHandler.setScrollView(scrMain);