ListView 항목 스크롤 애니메이션 ( "UIKit Dynamics"와 유사)
ListView
스크롤이 발생할 때 항목 에 애니메이션을 적용하려고합니다 . 보다 구체적으로, iOS 7의 iMessage 앱에서 스크롤 애니메이션을 에뮬레이트하려고합니다. 온라인 에서 비슷한 예를 찾았습니다 .
명확히하기 위해 새 항목이 추가 될 때 애니메이션이 아니라 사용자가 스크롤 할 때 항목에 "유동적 인"이동 효과를 얻으려고합니다. 나는 내에서 뷰를 수정하려고 시도했으며 어떻게 든 자식 뷰에 전송 된 그리기 좌표를 조정할 어딘가에 첨부 할 수 있는지 소스를 BaseAdapter
조사했습니다 (그것이 디자인 된 경우에도 ). 지금까지 진전이 없었습니다.AbsListView
AccelerateInterpolator
AbsListView
누구든지이 행동을 복제하는 방법에 대한 아이디어가 있습니까?
인터넷 검색에 도움이되는 레코드 : iOS 에서는 "UIKit Dynamics"라고 합니다.
최신 iOS 릴리스에 내장되어 있습니다. 그러나 여전히 사용하기가 다소 어렵습니다. (2014)이 글은 모두가 복사 한 것입니다. 널리 복사 된 기사 놀랍게도 UIKit Dynamics는 애플의 "테이블 뷰"가 아닌 애플의 "컬렉션 뷰"에서만 사용할 수 있으므로 모든 iOS 데브가 테이블 뷰에서 항목으로 변환해야합니다. "컬렉션보기"
모든 사람이 시작점으로 사용하는 라이브러리는 BPXLFlowLayout입니다 . 그 사람은 아이폰 문자 메시지 앱의 느낌을 거의 복사 해 내기 때문입니다. 사실, 당신이 그것을 안드로이드로 포팅한다면 같은 느낌을 얻기 위해 거기에있는 매개 변수를 사용할 수있을 것 같습니다. 참고로 내 안드로이드 폰 컬렉션에서 HTC 폰은 UI에 이러한 효과가 있음을 알았습니다. 도움이 되었기를 바랍니다. Android는 최고입니다!
이 구현은 꽤 잘 작동합니다. 어댑터가 상단 또는 하단에 새 뷰를 추가 할 때 인덱스가 변경 되었기 때문에 약간의 깜박임이 있습니다. 트리의 변경 사항을 확인하고 인덱스를 즉시 이동하여 해결할 수 있습니다.
public class ElasticListView extends GridView implements AbsListView.OnScrollListener, View.OnTouchListener {
private static int SCROLLING_UP = 1;
private static int SCROLLING_DOWN = 2;
private int mScrollState;
private int mScrollDirection;
private int mTouchedIndex;
private View mTouchedView;
private int mScrollOffset;
private int mStartScrollOffset;
private boolean mAnimate;
private HashMap<View, ViewPropertyAnimator> animatedItems;
public ElasticListView(Context context) {
super(context);
init();
}
public ElasticListView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ElasticListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
mScrollState = SCROLL_STATE_IDLE;
mScrollDirection = 0;
mStartScrollOffset = -1;
mTouchedIndex = Integer.MAX_VALUE;
mAnimate = true;
animatedItems = new HashMap<>();
this.setOnTouchListener(this);
this.setOnScrollListener(this);
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (mScrollState != scrollState) {
mScrollState = scrollState;
mAnimate = true;
}
if (scrollState == SCROLL_STATE_IDLE) {
mStartScrollOffset = Integer.MAX_VALUE;
mAnimate = true;
startAnimations();
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (mScrollState == SCROLL_STATE_TOUCH_SCROLL) {
if (mStartScrollOffset == Integer.MAX_VALUE) {
mTouchedView = getChildAt(mTouchedIndex - getPositionForView(getChildAt(0)));
if (mTouchedView == null) return;
mStartScrollOffset = mTouchedView.getTop();
} else if (mTouchedView == null) return;
mScrollOffset = mTouchedView.getTop() - mStartScrollOffset;
int tmpScrollDirection;
if (mScrollOffset > 0) {
tmpScrollDirection = SCROLLING_UP;
} else {
tmpScrollDirection = SCROLLING_DOWN;
}
if (mScrollDirection != tmpScrollDirection) {
startAnimations();
mScrollDirection = tmpScrollDirection;
}
if (Math.abs(mScrollOffset) > 200) {
mAnimate = false;
startAnimations();
}
Log.d("test", "direction:" + (mScrollDirection == SCROLLING_UP ? "up" : "down") + ", scrollOffset:" + mScrollOffset + ", toucheId:" + mTouchedIndex + ", fvisible:" + firstVisibleItem + ", " +
"visibleItemCount:" + visibleItemCount + ", " +
"totalCount:" + totalItemCount);
int indexOfLastAnimatedItem = mScrollDirection == SCROLLING_DOWN ?
getPositionForView(getChildAt(0)) + getChildCount() :
getPositionForView(getChildAt(0));
//check for bounds
if (indexOfLastAnimatedItem >= getChildCount()) {
indexOfLastAnimatedItem = getChildCount() - 1;
} else if (indexOfLastAnimatedItem < 0) {
indexOfLastAnimatedItem = 0;
}
if (mScrollDirection == SCROLLING_DOWN) {
setAnimationForScrollingDown(mTouchedIndex - getPositionForView(getChildAt(0)), indexOfLastAnimatedItem, firstVisibleItem);
} else {
setAnimationForScrollingUp(mTouchedIndex - getPositionForView(getChildAt(0)), indexOfLastAnimatedItem, firstVisibleItem);
}
if (Math.abs(mScrollOffset) > 200) {
mAnimate = false;
startAnimations();
mTouchedView = null;
mScrollDirection = 0;
mStartScrollOffset = -1;
mTouchedIndex = Integer.MAX_VALUE;
mAnimate = true;
}
}
}
private void startAnimations() {
for (ViewPropertyAnimator animator : animatedItems.values()) {
animator.start();
}
animatedItems.clear();
}
private void setAnimationForScrollingDown(int indexOfTouchedChild, int indexOflastAnimatedChild, int firstVisibleIndex) {
for (int i = indexOfTouchedChild + 1; i <= indexOflastAnimatedChild; i++) {
View v = getChildAt(i);
v.setTranslationY((-1f * mScrollOffset));
if (!animatedItems.containsKey(v)) {
animatedItems.put(v, v.animate().translationY(0).setDuration(300).setStartDelay(50 * i));
}
}
}
private void setAnimationForScrollingUp(int indexOfTouchedChild, int indexOflastAnimatedChild, int firstVisibleIndex) {
for (int i = indexOfTouchedChild - 1; i > 0; i--) {
View v = getChildAt(i);
v.setTranslationY((-1 * mScrollOffset));
if (!animatedItems.containsKey(v)) {
animatedItems.put(v, v.animate().translationY(0).setDuration(300).setStartDelay(50 * (indexOfTouchedChild - i)));
}
}
}
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
Rect rect = new Rect();
int childCount = getChildCount();
int[] listViewCoords = new int[2];
getLocationOnScreen(listViewCoords);
int x = (int)event.getRawX() - listViewCoords[0];
int y = (int)event.getRawY() - listViewCoords[1];
View child;
for (int i = 0; i < childCount; i++) {
child = getChildAt(i);
child.getHitRect(rect);
if (rect.contains(x, y)) {
mTouchedIndex = getPositionForView(child);
break;
}
}
return false;
}
return false;
}
}
나는 이것을 탐구하는 데 몇 분 밖에 걸리지 않았고 API 12 이상에서 매우 쉽게 수행 할 수있는 것처럼 보입니다 (아무것도 누락되지 않았 으면합니다 ...). 아주 기본적인 카드 효과를 얻으려면 어댑터의 getView () 끝에 몇 줄의 코드 만 있으면 목록에 반환됩니다. 다음은 전체 어댑터입니다.
public class MyAdapter extends ArrayAdapter<String>{
private int mLastPosition;
public MyAdapter(Context context, ArrayList<String> objects) {
super(context, 0, objects);
}
private class ViewHolder{
public TextView mTextView;
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
convertView = LayoutInflater.from(getContext()).inflate(R.layout.grid_item, parent, false);
holder.mTextView = (TextView) convertView.findViewById(R.id.checkbox);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.mTextView.setText(getItem(position));
// This tells the view where to start based on the direction of the scroll.
// If the last position to be loaded is <= the current position, we want
// the views to start below their ending point (500f further down).
// Otherwise, we start above the ending point.
float initialTranslation = (mLastPosition <= position ? 500f : -500f);
convertView.setTranslationY(initialTranslation);
convertView.animate()
.setInterpolator(new DecelerateInterpolator(1.0f))
.translationY(0f)
.setDuration(300l)
.setListener(null);
// Keep track of the last position we loaded
mLastPosition = position;
return convertView;
}
}
뷰를 아래에서 위로 (아래로 스크롤하는 경우) 또는 위에서 아래로 (위로 스크롤하는 경우) 애니메이션할지 여부를 결정하기 위해로드 할 마지막 위치 (mLastPosition)를 추적하고 있습니다.
멋진 점은 초기 convertView 속성 (예 : convertView.setScaleX (float scale))과 convertView.animate () 체인 (예 : .scaleX (float))을 수정하여 훨씬 더 많은 작업을 수행 할 수 있다는 것입니다.
Try this by putting this in your getView() method Just before returning your convertView:
Animation animationY = new TranslateAnimation(0, 0, holder.llParent.getHeight()/4, 0);
animationY.setDuration(1000);
Yourconvertview.startAnimation(animationY);
animationY = null;
Where llParent = RootLayout which consists your Custom Row Item.
It's honestly going to be a lot of work and quite mathematically intense, but I would have thought you could make the list item's layouts have padding top and bottom and that you could adjust that padding for each item so that the individual items become more or less spaced out. How you would track by how much and how you would know the speed at which the items are being scrolled, well that would be the hard part.
Since we do want items to pop every time they appear at the top or bottom of our list, the best place to do it is the getView() method of the adapter:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
animatePostHc(position, v);
} else {
animatePreHc(position, v);
}
From what I understand what you are looking for is a parallax effect.
This answer is really complete and I think that can help you a lot.
Use this library: http://nhaarman.github.io/ListViewAnimations
It is very awesome. Better than the iOS in atleast it is open source :)
참고URL : https://stackoverflow.com/questions/21588188/listview-item-scroll-animation-uikit-dynamics-like
'IT Share you' 카테고리의 다른 글
두 파일을 편집 한 다음 GitHub 웹 기반 편집기를 사용하여 하나의 커밋을 만들 수 있습니까? (0) | 2020.11.28 |
---|---|
내부 엔터프라이즈 개발에 Nuget을 어떻게 사용해야합니까? (0) | 2020.11.28 |
수은을 사용하여 svn : externals를 에뮬레이션 할 수 있습니까? (0) | 2020.11.28 |
단일 아포스트로피로 표시된 Rust 유형은 무엇입니까? (0) | 2020.11.28 |
파이썬에서 객체에 속성을 추가 할 수없는 이유는 무엇입니까? (0) | 2020.11.28 |