안 드 로 이 드 는 목록 리 셋 을 막 는 실현 방법 이 있 습 니 다.
이것 은 드 롭 다운 상태 입 니 다.
이것 은 손가락 을 내 려 놓 은 후 listView 가 새로 고침 상태 로 굴 러 갈 때의 모습 입 니 다.
1.어떻게 호출 합 니까?
비록 효과 도 는 모양 이 그다지 예 쁘 지 않 지만,주로 그 파란색 배경 이 맞 는 지,괜 찮 습 니 다.이것 은 배경 일 뿐 입 니 다.우리 의 드 롭 다운 리 셋 목록 의 실현 을 알 게 된 후에 당신 은 이 배경 을 쉽게 수정 하여 원 하 는 UI 효 과 를 실현 할 수 있 습 니 다!말 이 많 지 않 습 니 다.이 드 롭 다운 목록 을 어떻게 사용 하 는 지 먼저 말씀 드 리 겠 습 니 다.이것 도 저희 가 코드 를 작성 하여 실현 하고 자 하 는 목표 입 니 다.
final PullToRefreshListView eListView = (PullToRefreshListView) rootView.findViewById(R.id.profile_listView);
eListView.setOnLoadCallBack(new PullToRefreshListView.OnLoadCallBack() {
@Override
public int whereToLoad() {
return PullToRefreshListView.DEFAULT_WHERE_TO_LOAD;
}
@Override
public void onLoad() {
eListView.postDelayed(new Runnable() {
@Override
public void run() {
eListView.setLoadingFinish();
}
}, 5000);
}
@Override
public void cancelLoad() {
}
@Override
public Drawable refreshDrawable() {
return new ColorDrawable(Color.CYAN);
}
});
eListView.setAdapter(new BaseAdapter() {
@Override
public int getCount() {
return 30;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView tv;
if (convertView == null) {
tv = new TextView(getActivity());
tv.setGravity(Gravity.CENTER_VERTICAL);
tv.setHeight(200);
tv.setBackgroundColor(Color.WHITE);
} else {
tv = (TextView) convertView;
}
tv.setText(position+"");
return tv;
}
});
상기 코드 에서 PullToRefreshListView 의 사용 은 adapter 에서 ListView 와 같 습 니 다.물론 드 롭 다운 리 셋 기능 을 실현 하기 때문에 데이터 어댑터 를 수정 할 필요 가 없습니다.PullToRefreshListView 의 인 스 턴 스 는 OnLoadCallBack 리 셋 을 설정 해 야 합 니 다.이 리 셋 은 다음 과 같은 네 가지 방법 이 필요 합 니 다.
/**
*
*/
public interface OnLoadCallBack {
/**
* listView
* @return listView y ,in dp
*/
int whereToLoad();
/**
*
*/
void onLoad();
/**
*
*/
void cancelLoad();
/**
*
* @return drawable
*/
Drawable refreshDrawable();
}
where ToLoad 방법 은 PullToRefreshListView 대상 의 드 롭 다운 리 셋 시 어느 위치 에 머 무 르 는 지 알려 줍 니 다.구체 적 으로 말 하면 상기 제2 장 효과 그림 에서 파란색 배경의 높이 입 니 다.onLoad 방법 은 드 롭 다운 새로 고침 의 리 셋 입 니 다.호출 자 는 여기에서 새로 고침 동작 을 수행 할 수 있 습 니 다.cancelLoad 방법 은 새로 고침 동작 을 취소 하 는 것 입 니 다.호출 자 는 여기에서 새로 고침 동작 을 취소 해 야 합 니 다.상기 방법 에 따 르 면,onLoad 방법 에서 실행 되 는 것 은 하나의 스 레 드 나 AsyncTask 일 것 이 며,cancelLoad 방법 에서 해 야 할 일 은 이 스 레 드 나 AsyncTask 를 취소 하 는 것 이 라 고 추측 할 수 있 습 니 다.마지막 으로 refresh Drawable 방법 이 있 습 니 다.이 방법 은 listView 의 배경 을 수정 하기 위해 호출 자 에 게 제공 되 는 것 입 니 다.호출 자 는 좋아 하 는 배경 Drawable 을 되 돌려 줄 수 있 습 니 다.
어떻게 호출 하 는 지 알 게 된 후에 우 리 는 이 PullToRefreshListView 를 한 걸음 한 걸음 실현 해 야 한다.
2.dispatchDraw 에서 서브 View 를 다시 그 려 드 롭 다운 시각 을 실현 한다.
PullToRefreshListView 가 실현 하 는 관건 은 이 listVIEW 의 하위 View 를 다시 그 리 는 것 이다.View Group 을 다시 그 리 는 하위 View 는 일반적으로 dispatchDraw 방법 에서 이 루어 집 니 다.따라서 우리 의 PullToRefreshListView 는 ListView 류 에서 계승 하여 dispatchDraw 방법 을 다시 불 러 옵 니 다.
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (distanceY > 0) {
if (refreshDrawable == null) {
refreshDrawable = onLoadCallBack.refreshDrawable();
}
if (refreshDrawable == null) {
canvas.drawColor(Color.GRAY);
} else {
int left = getPaddingLeft();
int top = getPaddingTop();
refreshDrawable.setBounds(left, top, getWidth()+left, getHeight()+top);
refreshDrawable.draw(canvas);
}
canvas.save();
canvas.translate(getPaddingLeft(), getPaddingTop() + distanceY);
for (int i=0;i<getChildCount();i++) {
View child = getChildAt(i);
drawChild(canvas, child, getDrawingTime());
}
canvas.restore();
}
}
서브 뷰 를 다시 그 리 는 관건 은 이 코드 에 있다.
canvas.translate(getPaddingLeft(), getPaddingTop() + distanceY);
서브 뷰 를 다시 그리 기 전에,우 리 는 먼저 canvas 를 위로 이동 시 켜 distance Y 거 리 를 이동 해 야 한다.왜 그 럴 까요?캔버스 에 서브 뷰 를 그 리 는 방법 을 먼저 살 펴 보 겠 습 니 다.drawChild 방법의 문 서 는 어떻게 말 합 니까?
protected boolean drawChild (Canvas canvas, View child, long drawingTime)
Added in API level 1 Draw one child of this View Group. This method is responsible for getting the canvas in the right state. This includes clipping, translating so that the child's scrolled origin is at 0, 0, and applying any animation transformations.
Parameters canvas The canvas on which to draw the child child Who to draw drawingTime The time at which draw is occurring Returns True if an invalidate() was issued
draw Child 방법 으로 이 View Group 의 키 View 를 그 릴 수 있 습 니 다.이 방법 은 canvas 를 정확 한 상태 로 만들어 야 합 니 다.이 상 태 는...
canvas 에 대한 클립 재단,translate 평가 작업 등 을 통 해 이 하위 View 를 canvas 의(0,0)위치 에 두 는 것 입 니 다.
무슨 뜻 이 죠?쉽게 말 하면 drawChild 방법 은 child view 를 canvas(0,0)위치 에 그 리 므 로 이 child view 를
canvas 의 정확 한 위 치 는 다시 그리 기 전에 canvas 를 자 르 고 이동 하 는 등 작업 이 필요 합 니 다.예 를 들 어 canvas 하나 와 child view 가 있 습 니 다.
child view 는(0,0)위치 에 그 려 야 하기 때문에 우리 눈 앞 에 보 이 는 child view 는 canvas 의 꼭대기 에 있 습 니 다.그러나 그림 을 그리 기 전에 우 리 는...
canvas 는 100 개의 픽 셀 단 위 를 위로 이동 한 다음 child view 를(0,0)위치 에 그립 니 다.그러면 우리 눈 앞 에 보 이 는 child view 의 위 치 는?
canvas 의(0,100)위치 에 있 습 니 다.
상기 분석 에 의 하면 우 리 는 서브 뷰 를 다시 그 리 는 원 리 는 다음 과 같다 는 것 을 알 수 있다.
PullToRefreshListView 가 상단 까지 굴 러 갔 을 때 미끄럼 제스처 를 모니터링 하여 distance Y 를 계산 하여 canvas 를 위로 얼마나 이동 시 키 고 서브 View 를 다시 그 려 야 하 는 지 확인 하면 PullToRefreshListView 가 미끄럼 제스처 에 따라 아래로 당 기 는 기능 을 실현 할 수 있 습 니 다.
3.드 롭 다운 거리 계산
재 그림 을 실현 한 후에 우리 가 해 야 할 일 은 distance Y 를 어떻게 계산 하 는 것 입 니까?우리 의 초보적인 생각 은 미 끄 러 지 는 거리 에 따라 계산 하고 우리 가 댐퍼 효 과 를 실현 해 야 한 다 는 것 을 고려 하 는 것 이다.즉,미 끄 러 지 는 거리 가 길 어 지면 서 PullToRefreshListView 의 드 롭 다운 거 리 는 점점 짧 아 질 것 이다.PullToRefreshListView 실현 에서 저 는 지수 함 수 를 사용 하여 이 댐퍼 효 과 를 실현 합 니 다.구체 적 으로 계산 하면 다음 과 같 습 니 다.
distanceY = ev.getY() - pullStartY;
distanceY = (float) (Math.exp(-ev.getY() / pullStartY / 40) * distanceY);
우 리 는 마이너스 지 수 는 가속도 가 거리 에 따라 작 아 지 는 단조 로 운 증가 함수 라 는 것 을 알 고 있다.나 는 손가락 미끄럼 거 리 를 이용 하여 마이너스 지 수 를 계산 하 는 것 을 PullToRefreshListView 의 미끄럼 거 리 를 참고 기준 으로 하면 댐퍼 드 롭 다운 효 과 를 실현 할 수 있다.4.모니터 제스처 로 ListView 가 드 롭 다운 상태 에 들 어 갔 는 지 판단 하고 distanceY 업데이트
더 나 아가 우리 가 실현 하고 자 하 는 것 은 제스처 에 대한 감 시 였 다.PullToRefreshListView 에서 우 리 는 onTouchEvent 방법 에서 처리 했다.
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (lastAction == -1 && ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
//
lastAction = MotionEvent.ACTION_DOWN;
cancelAnimating();
L.d(TAG, "touch down");
} else if (lastAction == MotionEvent.ACTION_MOVE && ev.getActionMasked() == MotionEvent.ACTION_UP) {
// ,
isPulling = false;
lastAction = -1;
startAnimating();
L.d(TAG, "touch up");
} else if (lastAction == MotionEvent.ACTION_DOWN) {
if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) {
// ,
if (isTop && !isPulling) {
// listView ,
pullStartY = ev.getY();
lastAction = MotionEvent.ACTION_MOVE;
isPulling = true;
}
}
} else if (lastAction == MotionEvent.ACTION_MOVE) {
if (isTop) {
//
distanceY = ev.getY() - pullStartY;
L.d(TAG, distanceY + "");
if (distanceY > 0) {
distanceY = (float) (Math.exp(-ev.getY() / pullStartY / 40) * distanceY);
// move ,
ev.setAction(MotionEvent.ACTION_DOWN);
} else {
distanceY = 0;
// listView , move
ev.setAction(MotionEvent.ACTION_MOVE);
}
} else {
// listView listView , ,
lastAction = MotionEvent.ACTION_DOWN;
isPulling = false;
distanceY = 0;
}
}
return super.onTouchEvent(ev);
}
이 코드 는 상대 적 으로 좀 복잡 하 니 우 리 는 천천히 해석 합 시다.우선,저 희 는 lastAction 변 수 를 기록 하여 이전 제스처 가 무엇 인지 기록 합 니 다.isPulling 변 수 는 현재 PullToRefreshListView 가 드 롭 다운 상태 에 있 는 지,isTop 변 수 는 현재 PullToRefreshListView 가 위로 굴 러 갔 는 지 기록 합 니 다.onTouchEvent 방법의 과부하 실현 에서 처음에 PullToRefreshListView 는 어떠한 손짓 도 받 아들 이지 않 았 고 사용자 가 손가락 을 누 르 고 출발 할 때 ACTIONDOWN 이벤트 때,나 는 이 동작 을 기록 하고 사용자 가 미 끄 러 질 때,이때 PullToRefreshListView 가"위로 스크롤"하지 않 으 면 아무런 처리 도 하지 않 고,반대로 lastAction 을 ACTION 으로 업데이트 합 니 다.MOVE 상태 에서 isPulling 변 수 를 업데이트 하고 현재 손가락 의 위 치 를 드 롭 다운 거 리 를 계산 하 는 시작 위치 로 기록 하 며 드 롭 다운 새로 고침 을 시작 한 다음 드 롭 다운 과정 에서 PullToRefreshListView 드 롭 다운 거 리 를 계산 하여 하위 View 를 다시 그립 니 다.
이 제스처 처리 가 실 현 될 때 사용자 가 드 롭 다운 과정 에서 갑자기 PullToRefreshListView 를 위로 당 깁 니 다.PullToRefreshListView 를'위로 굴 러 가 는 상태'가 아 닌 상태 로 끌 어 올 리 면 드 롭 다운 상 태 를 초기 화 합 니 다.
lastAction = MotionEvent.ACTION_DOWN;
그래서 PullToRefreshListView 의 다음 하강 제스처 응답 권 은 시스템 에 넘 겨 졌 고 사용자 가 PullToRefreshListView 를'위로 스크롤'상태 로 끌 어 내 린 것 을 알 고 상기 조작 을 다시 실행 하여 PullToRefreshListView 를 드 롭 다운 상태 로 들 어 갔다.5.ListView 가 맨 위로 굴 러 갔 는 지 어떻게 판단 합 니까?
다음 단 계 는 ListView 가'위로 스크롤'상태 에 있 는 지 어떻게 판단 합 니까?이 문 제 는 PullToRefreshListView 의 onScroll 에서 해결 하 겠 습 니 다.
setOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
// view ( , view), listView
if (getChildCount() == 0) {
isTop = true;
return;
}
if (firstVisibleItem == 0) {
View firstView = getChildAt(0);
if (firstView.getTop() + distanceY >= 0) {
// view parent( listView) 0, listView
isTop = true;
return;
}
}
isTop = false;
}
});
PullToRefreshListView 에 OnScrollListener 리 셋 을 설정 하고 onScroll 방법 에서 스크롤 위 치 를 모니터링 합 니 다.구체 적 으로 주석 을 보면 한눈 에 알 수 있 습 니 다.저 는 더 이상 설명 하지 않 겠 습 니 다.6.드 롭 다운 후 스크롤 백 애니메이션
마지막 으로 손가락 을 떼 고 끝 낼 때 PullToRefreshListView 를 위해 스크롤 백 애니메이션 을 실행 해 야 합 니 다.onTouchEvent 방법 에서 보 았 습 니 다.
// ......
else if (lastAction == MotionEvent.ACTION_MOVE && ev.getActionMasked() == MotionEvent.ACTION_UP) {
// ,
isPulling = false;
lastAction = -1;
startAnimating();
L.d(TAG, "touch up");
}
// ......
startAnimating 방법의 실현 은 다음 과 같다.
/**
*
*/
private void startAnimating() {
int whereToLoad = dp2px(onLoadCallBack.whereToLoad());
final boolean toLoad;
if (distanceY <= whereToLoad) {
pullCancelAnimator = ValueAnimator.ofFloat(distanceY, 0);
toLoad = false;
} else {
pullCancelAnimator = ValueAnimator.ofFloat(distanceY, whereToLoad);
toLoad = true;
}
pullCancelAnimator.setDuration((long) (DEFAULT_BASE_ANIMATING_TIME_PER_100DP*px2dp(distanceY)/100));
pullCancelAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
pullCancelAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
distanceY = (float) animation.getAnimatedValue();
ViewCompat.postInvalidateOnAnimation(PullToRefreshListView.this);
}
});
pullCancelAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
post(new Runnable() {
@Override
public void run() {
pullCancelAnimator = null;
if (toLoad) {
onLoadCallBack.onLoad();
}
}
});
}
@Override
public void onAnimationCancel(Animator animation) {
post(new Runnable() {
@Override
public void run() {
pullCancelAnimator = null;
if (toLoad) {
onLoadCallBack.cancelLoad();
}
}
});
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
pullCancelAnimator.start();
}
저 는 ValueAnimator 를 사용 하여 이 스크롤 백 애니메이션 을 실 현 했 습 니 다.그 중에서 ValueAnimator 가 설정 한 리 셋 에서 애니메이션 업데이트 와 애니메이션 종료,애니메이션 취소 에서 OnLoadCallBack 의 3 곡 리 셋 방법 을 각각 호출 하여 PullToRefreshListView 의 드 롭 다운 리 셋 동작 을 실 현 했 습 니 다.onLoad 방법 은 UI 스 레 드 에서 실 행 된 것 을 볼 수 있 습 니 다.따라서 onLoad 방법 에서 시간 이 걸 리 면 배경 스 레 드 에서 작업 해 야 합 니 다.이것 은 우리 앞의 해석 과 대응 합 니 다.7.개선 과 문제점
(1)우 리 는 onLoad 리 셋 을 비동기 작업 대상 으로 되 돌아 가 는 방법 으로 수정 한 다음 에 PullToRefreshListView 를 드 롭 다운 이 끝 난 후에 이 비동기 작업 을 수행 할 수 있 습 니 다.따라서 우 리 는 cancelLoading 리 셋 이 필요 없 이 PullToRefreshListView 내부 에서 취소 작업 을 할 수 있 습 니 다.이렇게 하면 패키지 성 을 강화 할 수 있 습 니 다.그러나 현재 의 방법 에 비해 자유 도 는 그리 높 지 않다.
(2)스크롤 애니메이션 도 최적화 할 수 있 을 것 같 아 요.구체 적 으로 어떻게 최적화 해 야 할 지 저도 잘 모 르 겠 어 요.여러분,좋 은 생각 이 있 으 시 면 댓 글 창 에서 제안 해 주세요.감사합니다.
(3)드 롭 다운 할 때 멀 티 터치 에 대한 응답 이 완벽 하지 않 습 니 다.받 아들 일 수 있 지만 qq 클 라 이언 트 의 채 팅 목록 처럼 되 지 않 습 니 다.
8.소스 코드
이로써 저 는 드 롭 다운 리 셋 목록 을 어떻게 실현 하 는 지 분 석 했 습 니 다.PullToRefreshListView 의 소스 코드 는 다음 과 같 습 니 다.
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.AbsListView;
import android.widget.ListView;
import com.ivan.healthcare.healthcare_android.log.L;
/**
* listView
* Created by Ivan on 16/2/14.
*/
public class PullToRefreshListView extends ListView {
private final String TAG = "PullToRefreshListView";
private final int DEFAULT_BASE_ANIMATING_TIME_PER_100DP = 150;
public static final int DEFAULT_WHERE_TO_LOAD = 80;
private int lastAction = -1;
private float pullStartY = -1;
private boolean isTop = true;
private float distanceY = 0;
private boolean isPulling = false;
private ValueAnimator pullCancelAnimator;
private Context context;
private Drawable refreshDrawable;
private OnLoadCallBack onLoadCallBack = new OnLoadCallBack() {
@Override
public int whereToLoad() {
return DEFAULT_WHERE_TO_LOAD;
}
@Override
public void onLoad() {
}
@Override
public void cancelLoad() {
}
@Override
public Drawable refreshDrawable() {
return null;
}
};
public PullToRefreshListView(Context context) {
super(context);
initView(context);
}
public PullToRefreshListView(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
private void initView(Context context) {
this.context = context;
setOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
// view ( , view), listView
if (getChildCount() == 0) {
isTop = true;
return;
}
if (firstVisibleItem == 0) {
View firstView = getChildAt(0);
if (firstView.getTop() + distanceY >= 0) {
// view parent( listView) 0, listView
isTop = true;
return;
}
}
isTop = false;
}
});
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (lastAction == -1 && ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
//
lastAction = MotionEvent.ACTION_DOWN;
cancelAnimating();
L.d(TAG, "touch down");
} else if (lastAction == MotionEvent.ACTION_MOVE && ev.getActionMasked() == MotionEvent.ACTION_UP) {
// ,
isPulling = false;
lastAction = -1;
startAnimating();
L.d(TAG, "touch up");
} else if (lastAction == MotionEvent.ACTION_DOWN) {
if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) {
// ,
if (isTop && !isPulling) {
// listView ,
pullStartY = ev.getY();
lastAction = MotionEvent.ACTION_MOVE;
isPulling = true;
}
}
} else if (lastAction == MotionEvent.ACTION_MOVE) {
if (isTop) {
//
distanceY = ev.getY() - pullStartY;
L.d(TAG, distanceY + "");
if (distanceY > 0) {
distanceY = (float) (Math.exp(-ev.getY() / pullStartY / 40) * distanceY);
// move ,
ev.setAction(MotionEvent.ACTION_DOWN);
} else {
distanceY = 0;
// listView , move
ev.setAction(MotionEvent.ACTION_MOVE);
}
} else {
// listView listView , ,
lastAction = MotionEvent.ACTION_DOWN;
isPulling = false;
distanceY = 0;
}
}
return super.onTouchEvent(ev);
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (distanceY > 0) {
if (refreshDrawable == null) {
refreshDrawable = onLoadCallBack.refreshDrawable();
}
if (refreshDrawable == null) {
canvas.drawColor(Color.GRAY);
} else {
int left = getPaddingLeft();
int top = getPaddingTop();
refreshDrawable.setBounds(left, top, getWidth()+left, getHeight()+top);
refreshDrawable.draw(canvas);
}
canvas.save();
canvas.translate(getPaddingLeft(), getPaddingTop() + distanceY);
for (int i=0;i<getChildCount();i++) {
View child = getChildAt(i);
drawChild(canvas, child, getDrawingTime());
}
canvas.restore();
}
}
/**
*
*/
private void startAnimating() {
int whereToLoad = dp2px(onLoadCallBack.whereToLoad());
final boolean toLoad;
if (distanceY <= whereToLoad) {
pullCancelAnimator = ValueAnimator.ofFloat(distanceY, 0);
toLoad = false;
} else {
pullCancelAnimator = ValueAnimator.ofFloat(distanceY, whereToLoad);
toLoad = true;
}
pullCancelAnimator.setDuration((long) (DEFAULT_BASE_ANIMATING_TIME_PER_100DP*px2dp(distanceY)/100));
pullCancelAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
pullCancelAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
distanceY = (float) animation.getAnimatedValue();
ViewCompat.postInvalidateOnAnimation(PullToRefreshListView.this);
}
});
pullCancelAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
post(new Runnable() {
@Override
public void run() {
pullCancelAnimator = null;
if (toLoad) {
onLoadCallBack.onLoad();
}
}
});
}
@Override
public void onAnimationCancel(Animator animation) {
post(new Runnable() {
@Override
public void run() {
pullCancelAnimator = null;
if (toLoad) {
onLoadCallBack.cancelLoad();
}
}
});
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
pullCancelAnimator.start();
}
private void cancelAnimating() {
if (pullCancelAnimator != null) {
pullCancelAnimator.cancel();
}
}
private float px2dp(float pxvalue) {
return (pxvalue - 0.5f) /context.getResources().getDisplayMetrics().density;
}
private int dp2px(float dpvalue) {
return (int) (dpvalue * context.getResources().getDisplayMetrics().density + 0.5f);
}
/**
*
*/
public interface OnLoadCallBack {
/**
* listView
* @return listView y ,in dp
*/
int whereToLoad();
/**
*
*/
void onLoad();
/**
*
*/
void cancelLoad();
/**
*
* @return drawable
*/
Drawable refreshDrawable();
}
/**
*
* @param cb
*/
public void setOnLoadCallBack(OnLoadCallBack cb) {
this.onLoadCallBack = cb;
}
/**
* , listView
*/
public void setLoadingFinish() {
startAnimating();
}
}
이상 의 안 드 로 이 드 는 드 롭 다운 목록 을 리 셋 하 는 실현 방법 이 있 습 니 다.바로 작은 편집 이 여러분 에 게 공유 하 는 모든 내용 입 니 다.여러분 께 참고 가 되 고 저희 도 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.