Android Drag-Dismiss Activity

library_header

One of the highlights of the 6.0 release of Talon for Twitter, was a refresh of the drag-dismiss support, on the the profiles and tweet viewer.

I love an Activity that can be dismissed via a drag. It is really smooth, really simple, and makes for a great user experience. Being the open-source advocates that we are, it only felt right to put my new implementation out there, for everyone to use.

Being the open-source advocates that we are, it only felt right to put my new implementation out there, for everyone to use.

So today, I am happy to release my new Android-DragDismissActivity library, to everyone!

https://github.com/klinker24/Android-DragDismissActivity


Project Background

Previously, Jake and I had released a SlidingActivity library, that added a swipe-to-dismiss style, to any app. That library was a pretty big hit, but it came with some issues as well:

  • More restrictive in the types of content that you could put on it (no RecyclerView or ListView was a huge downside)
  • Hijacked your Toolbar and only let you use it for specific cases
  • Had much slower animations
  • It managed a bit too much of the content for you. This can be great for some, but a definite downside for others.

SlidingActivity was a great first step, but we knew we could do better, especially when Nick Butcher came out with Plaid and open-sourced a much more elastic drag-dismiss layout. This project was based off of a customized version of that ElasticDragDismissFrameLayout.

We first implemented that ElasticDragDismissFrameLayout in Pulse. Dragging up or down at the bottom or top of the message list brought you right back to your list of conversations.

Next up, Jake made a pretty awesome readability-style article viewer, with this same drag-dismiss style, at it's core. I was starting to love the way this looked, and worked! The obvious final step, for me, was abstracting it out, turning it into a library project, pulling it into Talon, then open-sourcing it for everyone. I am happy to finish that last step, today!

By the way, if you want to check out Jake's readability browser, it is completely open-source as well. It is so easy to include in your apps, I highly recommend trying it out!


Implementing the Drag-Dismiss Library

gif_of_list

Now the fun part, how do you include this new library in your project? Luckily for you, it is really easy and painless.

First up, include the dependency in your project:

dependencies {  
    ...
    compile 'com.klinkerapps:drag-dismiss-activity:1.4.0'
}

Now, the library comes with 2 flavors. For both implementations, I will set up and manage all the drag-dismiss related functionality, for you, so that you just have to worry about creating the content:

  1. A version that can host any type of content/views, so that you can directly add all of your current layouts, with very minimal changes!
  2. and a version that manages a RecyclerView implementation for you.

Note: The normal way to implement the drag-dismiss functionality is by extending the two provided activities: DragDismissActivity and DragDismissRecyclerViewActivity. If you would rather not do that, I have provided a delegate for each of these use-cases, that you can use: DragDismissDelegate and DragDismissRecyclerViewDelegate. To see an example of the delegate's usage, check out the AbstractDragDismissActivity.

Option 1 - Replacing a Normal Activity

For this version, I will wrap your content in a boilerplate UI that contains a Toolbar (if you want it) and a NestedScrollView, for your content.

  1. Within your AndroidManifest.xml, on your activity elements, replace whatever theme you are currently using with android:theme="@style/DragDismissTheme.
  2. Instead of extending AppCompatActivity, extend the DragDismissActivity.
  3. You won't want to override Activity#onCreate. Instead, override DragDismissActivity#onCreateContent. This method acts a bit like Fragment#onCreateView:
@Override
protected View onCreateContent(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {  
    View v = inflater.inflate(R.layout.activity_scrollable, parent, false);

    // do your normal view setup and Activity#onCreate lifecycle actions here, 
    // instead of within the Activity#onCreate.

    return v;
}

And you are done - doesn't get any easier than that!

One thing to note: if you are using Activity#findViewById, you will need to change it to use the View#findViewById, on the View that you created in the above function.

Option 2 - A Managed RecyclerView

If you are using an Activity that just has a RecyclerView in it, then this library can do all the heavy-lifting for you, all you will need to do is set it up with a RecyclerView.Adapter and a LayoutManager.

  1. Within your AndroidManifest.xml, on your Activity elements replace whatever theme you are currently using with android:theme="@style/DragDismissTheme.
  2. Within your activity, instead of extending AppCompatActivity, extend the DragDismissRecyclerViewActivity.
  3. You won't want to override Activity#onCreate. Instead, to set up your RecyclerView, override DragDismissRecyclerViewActivity#setupRecyclerView:
@Override
protected void setupRecyclerView(RecyclerView recyclerView) {  
    recyclerView.setLayoutManager(new LinearLayoutManager(this));
    recyclerView.setAdapter(new SampleAdapter());

    // do any other RecyclerView or Activity setup that needs to be done
}

That's it!


Customizing the Style

After implementing the steps above, you will get your old Activity, with drag-to-dismiss functionality at the top and the bottom of the layout, great! You probably want to customize it further though.

I have provided a DragDismissBundleBuilder that allows you to add customization to the DragDismissActivity through extras on an Intent:

Intent dragDismissActivity = new Intent(this, MyDragDismissActivity.class);

new DragDismissBundleBuilder(context)  
    .setTheme(DragDismissBundleBuilder.Theme.LIGHT)    // LIGHT (default), DARK, BLACK, DAY_NIGHT
    .setPrimaryColorResource(R.color.colorPrimary)    // defaults to a semi-transparent black
    .setToolbarTitle("Normal Activity Sample")        // defaults to null
    .setShowToolbar(true)                // defaults to true
    .setShouldScrollToolbar(true)       // defaults to true
    .setFullscreenOnTablets(false)      // defaults to false, tablets will have padding on each side
    .setDragElasticity(DragDismissIntentBuilder.DragElasticity.NORMAL)  // Larger elasticities will make it easier to dismiss.
    .build(dragDismissActivity);

// do anything else that you want to set up the Intent
// dragDismissActivity.putBoolean("test_bool", true);

startActivity(dragDismissActivity);  

Adding a ProgressBar

Have content that won't be loaded immediately? No problem.

While content is loading, you can call DragDismissActivity#showProgessBar to automatically show the progress indicator. When the content is done loading, just call DragDismissActivity#hideProgessBar to remove it.


Enjoy, and let me know what you want to see out of the library! If you like it, hit that star button on GitHub, or drop a comment below :)

If you include it in your apps, give me a shout out in the comments, would love to see what you have made with it!