Android Drag/Animation of Views

Android Drag/Animation of Views

Why can't you extend View? Then, you have complete control over how it draws because you can override the OnDraw() method. Just make the ColorBall class extend View. Change its position when you move and then invalidate just that one view and have it draw itself instead of having the DrawView class draw it.

Edit - Here is an example class

public class Card extends View
{
private Bitmap mImage;
private final Paint mPaint = new Paint();
private final Point mSize = new Point();
private final Point mStartPosition = new Point();

public Card(Context context)
{
super(context);

}

public final Bitmap getImage() { return mCardImage; }
public final void setImage(Bitmap image)
{
mImage = image;
setSize(mCardImage.getWidth(), mCardImage.getHeight());
}

@Override
protected void onDraw(Canvas canvas)
{
Point position = getPosition();
canvas.drawBitmap(mCardImage, position.x, position.y, mPaint);
}

public final void setPosition(final Point position)
{
mRegion.set(position.x, position.y, position.x + mSize.x, position.y + mSize.y);
}

public final Point getPosition()
{
Rect bounds = mRegion.getBounds();
return new Point(bounds.left, bounds.top);
}

public final void setSize(int width, int height)
{
mSize.x = width;
mSize.y = height;

Rect bounds = mRegion.getBounds();
mRegion.set(bounds.left, bounds.top, bounds.left + width, bounds.top + height);
}

public final Point getSize() { return mSize; }

@Override
public boolean onTouchEvent(MotionEvent event)
{
// Is the event inside of this view?
if(!mRegion.contains((int)event.getX(), (int)event.getY()))
{
return super.onTouchEvent(event);
}

if(event.getAction() == MotionEvent.ACTION_DOWN)
{
mStartPosition.x = (int)event.getX();
mStartPosition.y = (int)event.getY();
bringToFront();
onSelected();
return true;
}
else if(event.getAction() == MotionEvent.ACTION_MOVE)
{
int x = 0, y = 0;

if(mLock == DirectionLock.FREE || mLock == DirectionLock.HORIZONTAL_ONLY)
{
x = (int)event.getX() - mStartPosition.x;
}

if(mLock == DirectionLock.FREE || mLock == DirectionLock.VERTICAL_ONLY)
{
y = (int)event.getY() - mStartPosition.y;
}

mRegion.translate(x, y);
mStartPosition.x = (int)event.getX();
mStartPosition.y = (int)event.getY();

invalidate();

return true;
}
else
{
return super.onTouchEvent(event);
}
}
}

How to smoothly animate a view up/down based on a drag motion using ObjectAnimator?

Finally fixed the issue after reading Google's Chet Haase's answer to a similar question found here. https://stackoverflow.com/a/14780019/476005

Adjusting a view's margin on every frame is too expensive and will always stutter unless the View you're moving is very simple. So to fix this, I do the following in my OnTouch(...) method:

  1. On MotionEvent.ACTION_DOWN: Set the View's height to it's maximum height.
  2. On MotionEvent.ACTION_MOVE: Animate the View's "y" property to the event.getRawY with a duration of 0.
  3. On MotionEvent.ACTION_UP: Animate the View's "y" property to one of the View's parent's edges. The important thing to do here is to set the height of the View appropriately in onAnimationEnd.

I hope this helps everyone.

Show and hide a View with a slide up/down animation

With the new animation API that was introduced in Android 3.0 (Honeycomb) it is very simple to create such animations.

Sliding a View down by a distance:

view.animate().translationY(distance);

You can later slide the View back to its original position like this:

view.animate().translationY(0);

You can also easily combine multiple animations. The following animation will slide a View down by its height and fade it in at the same time:

// Prepare the View for the animation
view.setVisibility(View.VISIBLE);
view.setAlpha(0.0f);

// Start the animation
view.animate()
.translationY(view.getHeight())
.alpha(1.0f)
.setListener(null);

You can then fade the View back out and slide it back to its original position. We also set an AnimatorListener so we can set the visibility of the View back to GONE once the animation is finished:

view.animate()
.translationY(0)
.alpha(0.0f)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
view.setVisibility(View.GONE);
}
});

How to do touch and drag slide animation

You can do this using AndroidSlidingUpPanel. You can get the demo code from here: https://github.com/umano/AndroidSlidingUpPanel. Simply add the following dependency to your build.gradle file to use this.

compile 'com.sothree.slidinguppanel:library:3.2.1'

After that edit the following xml for your specific use:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".DemoActivity" >

<com.sothree.slidinguppanel.SlidingUpPanelLayout
xmlns:sothree="http://schemas.android.com/apk/res-auto"
android:id="@+id/sliding_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="bottom"
sothree:umanoPanelHeight="68dp"
sothree:umanoShadowHeight="4dp"
sothree:umanoParallaxOffset="100dp"
sothree:umanoDragView="@+id/dragView"
sothree:umanoOverlay="true"
sothree:umanoScrollableView="@+id/list">

<!-- MAIN CONTENT -->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
xmlns:sothree="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_toolbar"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
sothree:theme="@style/ActionBar"
android:layout_width="match_parent"/>
<TextView
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="?attr/actionBarSize"
android:gravity="center"
android:text="Main Content"
android:clickable="true"
android:focusable="false"
android:focusableInTouchMode="true"
android:textSize="16sp" />
</FrameLayout>

<!-- SLIDING LAYOUT -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
android:orientation="vertical"
android:clickable="true"
android:focusable="false"
android:id="@+id/dragView">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">

<TextView
android:id="@+id/name"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:textSize="14sp"
android:gravity="center_vertical"
android:paddingLeft="10dp"/>

<Button
android:id="@+id/follow"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textSize="14sp"
android:gravity="center_vertical|right"
android:paddingRight="10dp"
android:paddingLeft="10dp"/>

</LinearLayout>

</LinearLayout>
</com.sothree.slidinguppanel.SlidingUpPanelLayout>


Below the main MAIN CONTENT add your viewpager. Below SLIDING LAYOUT add your linear layout

UPDATE: AppCompat v23.2 have introduced BottomSheetBehavior behavior in CoordinatorLayout.

By attaching a BottomSheetBehavior to a child View of a CoordinatorLayout (i.e., adding app:layout_behavior=”android.support.design.widget.BottomSheetBehavior”), you’ll automatically get the appropriate touch detection to transition between five state:

  • STATE_COLLAPSED: this collapsed state is the default and shows just a
    portion of the layout along the bottom. The height can be controlled
    with the app:behavior_peekHeight attribute (defaults to 0)
  • STATE_DRAGGING: the intermediate state while the user is directly
    dragging the bottom sheet up or down
  • STATE_SETTLING: that brief time between when the View is released and
    settling into its final position
  • STATE_EXPANDED: the fully expanded state of the bottom sheet, where
    either the whole bottom sheet is visible (if its height is less than
    the containing CoordinatorLayout) or the entire CoordinatorLayout is
    filled
  • STATE_HIDDEN: disabled by default (and enabled with the
    app:behavior_hideable attribute), enabling this allows users to swipe
    down on the bottom sheet to completely hide the bottom sheet

You can get a sample app for implementing this from here: https://github.com/NikolaDespotoski/BottomSheetSample

How to stop animation of dragged view?

It's all about View.OnDragListener. In my example, I had OnDragListener only on topGrid. But if I set OnDragListener on both of them, everything works as expected. I guess, Android thinks that you did't handle drop event, cause view where you dropping item from top doesn't have dragListener

How to use a rotate animation while dragging view so center position keeps changing? To solve fromDegree toDegree issue

As you move the view, the center of the rotation remains at the starting location but the view still moves five degrees back and forth, so it is like moving from the center of a merry-go-round to the periphery where the five degree movement covers a greater distance in the same amount of time.

I suggest that you move to an ObjectAnimator which does not have this problem.

ObjectAnimator

This subclass of ValueAnimator provides support for animating properties on target objects. The constructors of this class take parameters to define the target object that will be animated as well as the name of the property that will be animated. Appropriate set/get functions are then determined internally and the animation will call these functions as necessary to animate the property.

jiggle.xml


This is a new ObjectAnimator xml for the jiggle effect. It is very similar to your jiggle.xml.

<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="100"
android:propertyName="rotation"
android:repeatCount="-1"
android:repeatMode="reverse"
android:valueFrom="-5"
android:valueTo="5"
android:valueType="floatType" />

VHItem

Updated view holder with animator support.

class VHItem extends RecyclerView.ViewHolder {
private ImageView ivCollectionImage, ivRemoveIcon;
private RelativeLayout rlContainer;
private Animator mAnimator;

public VHItem(View itemView) {
super(itemView);
ivCollectionImage = itemView.findViewById(R.id.ivCollectionImage);
ivRemoveIcon = itemView.findViewById(R.id.ivRemoveIcon);
rlContainer = itemView.findViewById(R.id.rlContainer);
}

// Start animation. Inflate the animator lazily.
public void startAnimator() {
if (mAnimator == null) {
mAnimator = AnimatorInflater.loadAnimator(context, R.animator.jiggle);
}
mAnimator.setTarget(itemView);
mAnimator.start();
}

// Stop the animation. Set the rotation back to zero.
public void stopAnimator() {
if (mAnimator != null) {
itemView.setRotation(0);
mAnimator.cancel();
}
}
}

You will need to update the rest of the adapter to work with the new animation.



Related Topics



Leave a reply



Submit