Open liuwei-tapatalk opened 7 years ago
@h6ah4i Thanks for your sample! I tried your solution and it works very well. But I still have two question about it.
Q1. Why we need PAYLOAD_DRAGGABLE_ITEM_CHANGED
? I think we can simplified the code as below :
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
final AbstractDataProvider.Data item = mProvider.getItem(position);
holder.mTextView.setText(item.getText());
final int dragState = holder.getDragStateFlags();
// Just remove it. if (draggableChanged || ((dragState & Draggable.STATE_FLAG_IS_UPDATED) != 0)) {
int bgResId;
if ((dragState & Draggable.STATE_FLAG_IS_ACTIVE) != 0) {
bgResId = R.drawable.bg_item_dragging_active_state;
DrawableUtils.clearState(holder.mContainer.getForeground());
} else if ((dragState & Draggable.STATE_FLAG_DRAGGING) != 0) {
bgResId = R.drawable.bg_item_dragging_state;
} else {
bgResId = R.drawable.bg_item_normal_state;
}
holder.mContainer.setBackgroundResource(bgResId);
// Remove it }
if ((((dragState & Draggable.STATE_FLAG_IS_ACTIVE) != 0) || (dragState & Draggable.STATE_FLAG_DRAGGING) == 0)
&& (position == mDraggableItemPosition)) {
holder.mContainer.setBackgroundResource(R.drawable.bg_item_dragging_active_state);
ViewCompat.setScaleX(holder.itemView, 1.2f);
ViewCompat.setScaleY(holder.itemView, 1.2f);
ViewCompat.setTranslationZ(holder.itemView, 2.0f);
} else {
ViewCompat.setScaleX(holder.itemView, 1.0f);
ViewCompat.setScaleY(holder.itemView, 1.0f);
ViewCompat.setTranslationZ(holder.itemView, 0.0f);
}
}
Q2. How can I add animation when it scale? I want add animation when it enter 'drag state' from 'normal state'. I tried some code as below, but it works very weird. Firstly it will scale up with animation as expect. But when onAnimationEnd, it will scale down to normal size then scale up to large size immediately.
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
//....Some code....
if ((((dragState & Draggable.STATE_FLAG_IS_ACTIVE) != 0) || (dragState & Draggable.STATE_FLAG_DRAGGING) == 0)
&& (position == mDraggableItemPosition)) {
holder.mContainer.setBackgroundResource(R.drawable.bg_item_dragging_active_state);
Animation anim1 = new ScaleAnimation(1f, 1.2f, 1f, 1.2f, Animation.RELATIVE_TO_SELF,
0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
Animation anim2 = new AlphaAnimation(1f, 0.95f);
final AnimationSet as = new AnimationSet(true);
as.addAnimation(anim1);
as.addAnimation(anim2);
as.setFillAfter(false);
as.setDuration(250);
final View v = holder.itemView;
as.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
// nothing
}
@Override
public void onAnimationEnd(Animation animation) {
v.clearAnimation();
ViewCompat.setScaleX(v, 1.2f);
ViewCompat.setScaleY(v, 1.2f);
ViewCompat.setTranslationZ(v, 2.0f);
}
@Override
public void onAnimationRepeat(Animation animation) {
// nothing
}
});
holder.itemView.startAnimation(as);
} else {
ViewCompat.setScaleX(holder.itemView, 1.0f);
ViewCompat.setScaleY(holder.itemView, 1.0f);
ViewCompat.setTranslationZ(holder.itemView, 0.0f);
}
Thanks for your help again and waiting for your reply!
By the way, for the original question, my solution as below:
private void showMoveItemAnim(final View view) {
float scale = 1.2f;
Animation anim1 = new ScaleAnimation(1f, scale, 1f, scale, Animation.RELATIVE_TO_SELF,
0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
Animation anim2 = new AlphaAnimation(1f, 0.95f);
final AnimationSet as = new AnimationSet(true);
as.addAnimation(anim1);
as.addAnimation(anim2);
as.setFillAfter(true);
as.setDuration(250);
view.startAnimation(as);
view.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_MOVE
|| event.getAction() == MotionEvent.ACTION_UP) {
(new Handler()).postDelayed(new Runnable() {
@Override
public void run() {
v.clearAnimation();
}
}, 200);
view.setOnTouchListener(null);
}
return false;
}
});
}
My solution can provide animation when it enter draggable state, but I'm not sure when is the best time to clearAnimation, so I clearAnimation after 200ms. I think my code is very ugly 👎
@liuwei-tapatalk
Q1. Why we need PAYLOAD_DRAGGABLE_ITEM_CHANGED ? I think we can simplified the code as below:
That's okay. No problem at all.
Q2. How can I add animation when it scale? I want add animation when it enter 'drag state' from 'normal state'. I tried some code as below, but it works very weird. Firstly it will scale up with animation as expect. But when onAnimationEnd, it will scale down to normal size then scale up to large size immediately.
Manipulating animations for itemView
directly is not safe. Animations should always be handled through an ItemAnimator
, without the manner it will lead fatal inconsistency inside of the RecyclerView (and ending in weird exceptions).
ref.: https://medium.com/master-of-code-global/recyclerview-tips-and-recipes-476410fa12fd related issues: #336, #26, #315
EDIT: Found a good article creating a custom ItemAnimator
.
http://frogermcs.github.io/recyclerview-animations-androiddevsummit-write-up/
FYI, DefaultItemAnimator
implementation looks a bit complicated so this library provides RefactoredDefaultItemAnimator
which provides the same behavior with more cleaned up code base.
Sorry for reply so late. I still can not implement this animation perfectly. And I don't know how to describe the problem.
After many attempts, I think the best solution is your implement in https://github.com/h6ah4i/android-advancedrecyclerview/commit/fcd2f31fc565d877d736276c440e384f91238986.
Hi, I'm working on such behavior : long click item -> show a dialog -> select 'move' on the dialog -> the item should floats up, then user can drag it and move.
I know I can use
dragManager.setDraggingItemScale(1.2f)
to make item floats up. But it only work when user start to drag. What I want is making the item floats up before user start to drag. Is there anyway to do it?