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:
- On MotionEvent.ACTION_DOWN: Set the View's height to it's maximum height.
- On MotionEvent.ACTION_MOVE: Animate the View's "y" property to the event.getRawY with a duration of 0.
- 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
How to Stop Scrolling in a Gallery Widget
Custom Translucent Android Actionbar
Progress Bar While Loading Image Using Glide
Differencebetween Sendstickybroadcast and Sendbroadcast in Android
Get List of Active Pendingintents in Alarmmanager
Which View Should Be Used for New Material Design Bottom Navigation
Making a Linearlayout Act Like an Button
Otp (Token) Should Be Automatically Read from the Message
Don't Collapse Toolbar When Recyclerview Fits the Screen
Running Emulator After Building Android from Source
How to Prevent a Scrollview from Scrolling to a Webview After Data Is Loaded
Android Translate Animation - Permanently Move View to New Position Using Animationlistener
How to Bring View in Front of Everything
How to Display Multiple Notifications in Android
Android Marshmallow: Test Permissions with Espresso