今天说最近自己遇到的一个问题,就是要用动画效果来移动一个VIew的位置。
这个具体的情况是,需要做一个SlidingMenu的app,之前找了一个开源的,但不知道为什么,用起来app的运行效率很低,会有卡顿的现象。无奈只要自己写了。
SlidingMenu核心的就是可以滑动拉开左侧和右侧的菜单。刚开始考虑用TranslationAnimation来做。不过TranslationAnimation并不是真的移动一个View的坐标,在网上找了找,需要在Animation结束的时候,重新去layout下View的坐标,经过测试,这个方式可以达到预期效果。代码如下:
final int xOffset = leftFrameLayout.getWidth(); TranslateAnimation translateAnimation = new TranslateAnimation(0, xOffset, 0, 0); translateAnimation.setDuration(200); translateAnimation.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { //To change body of implemented methods use File | Settings | File Templates. } @Override public void onAnimationEnd(Animation animation) { int left = xOffset; int top = centerFrameLayout.getTop(); int width = centerFrameLayout.getWidth(); int height = centerFrameLayout.getHeight(); centerFrameLayout.clearAnimation(); centerFrameLayout.layout(left, top, left + width, top + height); leftFrameLayout.bringToFront(); } @Override public void onAnimationRepeat(Animation animation) { //To change body of implemented methods use File | Settings | File Templates. } }); centerFrameLayout.startAnimation(translateAnimation);貌似没什么问题了,不过我的界面中,当显示SldingMenu的侧边栏的时候,里面有个输入框,点击输入框弹出键盘的时候,会导致界面重新layout,这时候中间被移动的view,就又给自动移动回来了,看来用
centerFrameLayout.layout无法解决键盘弹出时候的重绘。
这时考虑到使用Scroller类来进行动画移动。也是参考了网上的例子,将我中间部分的FrameLayout搞成一个自定义类,代码如下:
public class ScrollableFrameLayout extends FrameLayout { private Scroller scroller; public ScrollableFrameLayout(Context context) { super(context); init(); } public ScrollableFrameLayout(Context context, AttributeSet attrs) { super(context, attrs); init(); } public ScrollableFrameLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } private void init(){ scroller = new Scroller(getContext()); } @Override public void scrollTo(int x, int y) { super.scrollTo(x, y); postInvalidate(); } @Override public void computeScroll() { if (!scroller.isFinished()) { if (scroller.computeScrollOffset()) { int oldX = getScrollX(); int oldY = getScrollY(); int x = scroller.getCurrX(); int y = scroller.getCurrY(); if (oldX != x || oldY != y) { scrollTo(x, y); } // Keep on drawing until the animation has finished. invalidate(); } else { clearChildrenCache(); } } else { clearChildrenCache(); } } public void smoothScrollTo(int dx, int duration) { int oldScrollX = getScrollX(); scroller.startScroll(oldScrollX, getScrollY(), dx, getScrollY(), duration); invalidate(); } private void enableChildrenCache() { final int count = getChildCount(); for (int i = 0; i < count; i++) { final View layout = (View) getChildAt(i); layout.setDrawingCacheEnabled(true); } } private void clearChildrenCache() { final int count = getChildCount(); for (int i = 0; i < count; i++) { final View layout = (View) getChildAt(i); layout.setDrawingCacheEnabled(false); } }}然后在需要移动这个类的地方调用:
int xOffset = rightFrameLayout.getWidth(); centerFrameLayout.bringToFront(); centerFrameLayout.smoothScrollTo(-xOffset, SCROLL_DURATION); handler.postDelayed(new Runnable() { @Override public void run() { rightFrameLayout.setVisibility(View.INVISIBLE); } }, SCROLL_DURATION);
问题完美解决