gpt4 book ai didi

android - ListView 项目滚动动画 ("UIKit Dynamics"-like)

转载 作者:IT老高 更新时间:2023-10-28 13:21:01 24 4
gpt4 key购买 nike

我试图在滚动发生时为 ListView 项设置动画。更具体地说,我正在尝试在 iOS 7 上模拟 iMessage 应用程序的滚动动画。我发现了一个类似的示例 online :

为了澄清,我试图在用户滚动时实现项目的“流畅”移动效果,而不是添加新项目时的动画。我试图修改 BaseAdapter 中的 View ,并查看了 AbsListView 源代码,看看是否可以附加 AccelerateInterpolator在某个地方可以调整发送到 subview 的绘制坐标(如果这就是 AbsListView 的设计方式)。到目前为止,我一直无法取得任何进展。

有人知道如何复制这种行为吗?


为了帮助使用谷歌搜索记录:这在 ios 上称为 “UIKit Dynamics”

How to replicate Messages bouncing bubbles in iOS 7

它内置于最近的 iOS 版本中。不过使用起来还是有点难度。 (2014) 这是每个人都复制的帖子:widely copied article令人惊讶的是,UIKit Dynamics 仅适用于苹果的“ Collection View ”,而不是苹果的“表格 View ”,因此所有 iOS debs 都必须将内容从表格 View 转换为“ Collection View ”

每个人都使用的库是 BPXLFlowLayout,因为那个人非常擅长复制 iphone 短信应用程序的感觉。事实上,如果你将它移植到 Android,我想你可以使用其中的参数来获得相同的感觉。仅供引用,我在我的 android fone 收藏中注意到,HTC 手机在其 UI 上具有这种效果。希望能帮助到你。 Android 摇滚!

最佳答案

这个实现效果很好。虽然有一些闪烁,可能是因为当适配器将新 View 添加到顶部或底部时更改了索引..这可能通过观察树中的变化并动态移动索引来解决..

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;

}

}

关于android - ListView 项目滚动动画 ("UIKit Dynamics"-like),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21588188/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com