我想使用插值器减速SlidingDrawer开启速度(DecelerateInterpolator) 这可能吗。我想实现轻松动画。
final Animation slowDown = AnimationUtils.loadAnimation(((Swipe)getActivity()), R.anim.ease);
这是XML
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/decelerate_interpolator">
<translate
android:fromYDelta="0"
android:toYDelta="100%p"
android:duration="2000"/>
</set>
使用这个我没有得到我想要的东西。
答案 0 :(得分:0)
实际上,如果您只想打开/关闭该滑动布局,那么我建议使用自定义ViewGroup
而不是弃用SlidingDrawer
。以下是该实现的一些简单示例:
public class MySimpleSlidingDrawer extends RelativeLayout implements View.OnClickListener {
private static final int SLIDING_TIME = 500;
private View mHandle;
private int mHandleId;
private View mContent;
private int mContentId;
private ObjectAnimator mOpenAnimator = ObjectAnimator.ofFloat(this, "slide", 0f, 1f);
private ObjectAnimator mCloseAnimator = ObjectAnimator.ofFloat(this, "slide", 1f, 0f);
private int mAnimationTime = SLIDING_TIME;
private boolean mOpened = false;
private int mSlideHeight = 0;
public MySimpleSlidingDrawer(final Context context) {
super(context);
init(context, null, 0);
}
public MySimpleSlidingDrawer(final Context context, final AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0);
}
public MySimpleSlidingDrawer(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
init(context, attrs, defStyle);
}
private void init(final Context context, final AttributeSet attrs, final int defStyle) {
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MySlidingDrawer, defStyle, 0);
mHandleId = a.getResourceId(R.styleable.MySlidingDrawer_handle, 0);
mContentId = a.getResourceId(R.styleable.MySlidingDrawer_content, 0);
mOpenAnimator.setInterpolator(new AccelerateInterpolator());
mOpenAnimator.setDuration(SLIDING_TIME);
mCloseAnimator.setInterpolator(new DecelerateInterpolator());
mCloseAnimator.setDuration(SLIDING_TIME);
setClipChildren(false);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
if (getChildCount() != 2) {
throw new InflateException("Only to child are supported for this layout");
}
if (mHandleId != 0) {
mHandle = findViewById(mHandleId);
} else {
mHandle = getChildAt(0);
}
if (mContentId != 0) {
mContent = findViewById(mContentId);
} else {
mContent = getChildAt(1);
}
final LayoutParams handleParams = (LayoutParams) mHandle.getLayoutParams();
handleParams.width = ViewGroup.LayoutParams.WRAP_CONTENT;
handleParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
handleParams.addRule(ALIGN_PARENT_BOTTOM, 1/* true */);
handleParams.addRule(CENTER_HORIZONTAL, 1/* true */);
mHandle.setLayoutParams(handleParams);
mHandle.setOnClickListener(this);
}
@Override
public void onClick(final View v) {
if (mSlideHeight == 0) {
mSlideHeight = getHeight() - mHandle.getHeight();
}
// Handle have been clicked. Execute animation depending on open / close state
if (!mOpened) {
mOpened = true;
mCloseAnimator.cancel();
mOpenAnimator.start();
} else {
mOpened = false;
mOpenAnimator.cancel();
mCloseAnimator.start();
}
}
/**
* Sets slide percent value
*
* @param slidePercent % of slide (0 - closed, 1 - opened)
*/
@SuppressWarnings("UnusedDeclaration")
public void setSlide(final float slidePercent) {
final LayoutParams handleParams = (LayoutParams) mHandle.getLayoutParams();
handleParams.bottomMargin = (int) (slidePercent * mSlideHeight);
mHandle.setLayoutParams(handleParams);
final LayoutParams contentParams = (LayoutParams) mContent.getLayoutParams();
contentParams.bottomMargin = (int) -((1- slidePercent) * mSlideHeight);
mContent.setLayoutParams(contentParams);
}
/**
* Sets open interpolator
*
* @param interpolator {@link android.view.animation.Interpolator} for open animation
*/
@SuppressWarnings("UnusedDeclaration")
public void setOpenInterpolator(final Interpolator interpolator) {
if (mOpenAnimator.isRunning()) {
mOpenAnimator.cancel();
}
mOpenAnimator.setInterpolator(interpolator);
}
/**
* Sets close interpolator
*
* @param interpolator {@link android.view.animation.Interpolator} for close animation
*/
@SuppressWarnings("UnusedDeclaration")
public void setCloseInterpolator(final Interpolator interpolator) {
if (mCloseAnimator.isRunning()) {
mCloseAnimator.cancel();
}
mCloseAnimator.setInterpolator(interpolator);
}
@Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// Trick to avoid content to be resized - measure it as it visible
final int contentHeightMeasure = MeasureSpec.makeMeasureSpec(getMeasuredHeight() - mHandle.getMeasuredHeight(), MeasureSpec.EXACTLY);
final int contentWidthMeasure = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY);
mContent.measure(contentHeightMeasure, contentWidthMeasure);
if (mSlideHeight == 0) {
mSlideHeight = getMeasuredHeight() - mHandle.getMeasuredHeight();
final LayoutParams contentParams = (LayoutParams) mContent.getLayoutParams();
contentParams.height = mSlideHeight;
contentParams.addRule(ALIGN_PARENT_BOTTOM, 1 /* true */);
contentParams.bottomMargin = - mSlideHeight;
mContent.setLayoutParams(contentParams);
}
}
}
注意:它没有经过优化或测试,但基本功能有效。
另一种方法是根据您的需要调整现有的SlidingDrawer
代码。对我来说,它看起来不那么容易或灵活,因为它具有特定的现有实现。首先,它在SlidingDrawer文档中明确提到:
不再支持此课程。建议您以此为基础 自己实现Android开源的源代码 项目,如果您必须在您的应用程序中使用它。
SlidingDrawer
没有公开动画更改API。主要问题是根本没有动画,有些计时事件只是发送到更新视图位置,这里:
private void doAnimation() {
if (mAnimating) {
incrementAnimation();
if (mAnimationPosition >= mBottomOffset + (mVertical ? getHeight() : getWidth()) - 1) {
mAnimating = false;
closeDrawer();
} else if (mAnimationPosition < mTopOffset) {
mAnimating = false;
openDrawer();
} else {
moveHandle((int) mAnimationPosition);
mCurrentAnimationTime += ANIMATION_FRAME_DURATION;
mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE),
mCurrentAnimationTime);
}
}
}
因此,为了修改插值,您需要更改动画逻辑或提供自己的动画逻辑。第二种方式更安全,因为不会影响现有逻辑。下面是一些草稿变体如何做到(检测与原始SlidingDrawer
相比,在您的Android SDK安装中使用原始API 19版本打开下面的类差异的原始public class MySlidingDrawer extends ViewGroup {
/** Click animation duration */
// TODO: ideally you should properly calculate that value
private static final long CLICK_ANIMATION_DURATION = 1000;
/** New field for custom interpolator */
private TimeInterpolator mAnimationInterpolator = new BounceInterpolator();
/** just to distinguish click and moving by user animations */
private boolean mAnimatedClick = false;
/** Specific click animator */
private ObjectAnimator mClickToggleAnimation;
/** Specific listener just to handle animation end properly */
private Animator.AnimatorListener mClickAnimationListener = new Animator.AnimatorListener() {
@Override
public void onAnimationStart(final Animator animation) {
// nothing to do here
}
@Override
public void onAnimationEnd(final Animator animation) {
mAnimating = false;
// Determine if it close or open, by comparing to some final value
if (mAnimationPosition == mTopOffset) {
openDrawer();
} else {
closeDrawer();
}
}
@Override
public void onAnimationCancel(final Animator animation) {
// TODO: should be handled properly
}
@Override
public void onAnimationRepeat(final Animator animation) {
}
};
...
/**
* Creates a new SlidingDrawer from a specified set of attributes defined in XML.
*
* @param context The application's environment.
* @param attrs The attributes defined in XML.
*/
public MySlidingDrawer(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
...
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mLocked) {
return true;
}
if (mTracking) {
mVelocityTracker.addMovement(event);
final int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_MOVE:
moveHandle((int) (mVertical ? event.getY() : event.getX()) - mTouchDelta);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
final VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(mVelocityUnits);
float yVelocity = velocityTracker.getYVelocity();
float xVelocity = velocityTracker.getXVelocity();
boolean negative;
final boolean vertical = mVertical;
if (vertical) {
negative = yVelocity < 0;
if (xVelocity < 0) {
xVelocity = -xVelocity;
}
if (xVelocity > mMaximumMinorVelocity) {
xVelocity = mMaximumMinorVelocity;
}
} else {
negative = xVelocity < 0;
if (yVelocity < 0) {
yVelocity = -yVelocity;
}
if (yVelocity > mMaximumMinorVelocity) {
yVelocity = mMaximumMinorVelocity;
}
}
float velocity = (float) Math.hypot(xVelocity, yVelocity);
if (negative) {
velocity = -velocity;
}
final int top = mHandle.getTop();
final int left = mHandle.getLeft();
if (Math.abs(velocity) < mMaximumTapVelocity) {
if (vertical ? (mExpanded && top < mTapThreshold + mTopOffset) ||
(!mExpanded && top > mBottomOffset + getBottom() - getTop() -
mHandleHeight - mTapThreshold) :
(mExpanded && left < mTapThreshold + mTopOffset) ||
(!mExpanded && left > mBottomOffset + getRight() - getLeft() -
mHandleWidth - mTapThreshold)) {
if (mAllowSingleTap) {
playSoundEffect(SoundEffectConstants.CLICK);
animateToggle();
/*
if (mExpanded) {
animateClose(vertical ? top : left);
} else {
animateOpen(vertical ? top : left);
}
*/
} else {
performFling(vertical ? top : left, velocity, false);
}
} else {
performFling(vertical ? top : left, velocity, false);
}
} else {
performFling(vertical ? top : left, velocity, false);
}
}
break;
}
}
return mTracking || mAnimating || super.onTouchEvent(event);
}
...
/**
* Toggles the drawer open and close with an animation.
*
* @see #open()
* @see #close()
* @see #animateClose()
* @see #animateOpen()
* @see #toggle()
*/
public void animateToggle() {
mAnimatedClick = true;
if (!mExpanded) {
animateClickOpen();
} else {
animateClickClose();
}
}
/**
* For doing our animation for close
*/
private void animateClickClose() {
mAnimating = true;
mClickToggleAnimation = ObjectAnimator.ofInt(this, "togglePosition", (int) mAnimationPosition, mBottomOffset + (mVertical ? getHeight() : getWidth()) - 1);
mClickToggleAnimation.setInterpolator(mAnimationInterpolator);
mClickToggleAnimation.setDuration(CLICK_ANIMATION_DURATION);
mClickToggleAnimation.addListener(mClickAnimationListener);
mClickToggleAnimation.start();
}
/**
* For doing our animation for open
*/
private void animateClickOpen() {
mAnimating = true;
mClickToggleAnimation = ObjectAnimator.ofInt(this, "togglePosition", (int)mAnimationPosition, mTopOffset);
mClickToggleAnimation.setInterpolator(mAnimationInterpolator);
mClickToggleAnimation.setDuration(CLICK_ANIMATION_DURATION);
mClickToggleAnimation.addListener(mClickAnimationListener);
mClickToggleAnimation.start();
}
/**
* Sets current animation position
*
* @param position to be set
*/
@SuppressWarnings("UnusedDeclaration")
public void setTogglePosition(final int position) {
mAnimationPosition = position;
moveHandle((int) mAnimationPosition);
}
...
private class DrawerToggler implements OnClickListener {
public void onClick(View v) {
if (mLocked) {
return;
}
// mAllowSingleTap isn't relevant here; you're *always*
// allowed to open/close the drawer by clicking with the
// trackball.
if (mAnimateOnClick) {
animateToggle();
} else {
toggle();
}
}
}
...
/**
* New API to modify timing of interpolator
*
* @param interpolator {@link android.animation.TimeInterpolator} to be used for onClick open / close
*
* TODO: it's also possible to add XML attribute for the same
*/
public void setAnimationInterpolator(final TimeInterpolator interpolator) {
mAnimationInterpolator = interpolator;
}
}
),只有更改的代码如下所示:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res/com.alexstarc.testapp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- Some fragment with main content of activity screen -->
<fragment
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.alexstarc.testapp.VoteListFragment"
android:tag="mainFragment"/>
<com.alexstarc.testapp.MySlidingDrawer
android:id="@+id/drawer"
android:layout_width="match_parent"
android:layout_height="match_parent"
custom:handle="@+id/handle"
custom:orientation="vertical"
custom:content="@+id/content">
<ImageView
android:id="@id/handle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@android:drawable/ic_delete"/>
<ImageView
android:id="@id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/cover"
android:scaleType="fitXY"/>
</com.alexstarc.testapp.MySlidingDrawer>
<!--
<com.alexstarc.testapp.MySimpleSlidingDrawer
android:id="@+id/drawer"
android:layout_width="match_parent"
android:layout_height="match_parent"
custom:handle="@+id/handle"
custom:content="@+id/content">
<ImageView
android:id="@id/handle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@android:drawable/ic_delete"/>
<ImageView
android:id="@id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/cover"
android:scaleType="fitXY"/>
</com.alexstarc.testapp.MySimpleSlidingDrawer>
-->
</RelativeLayout>
还有我用于测试的xml(只应启用一个滑动抽屉部分):
{{1}}