Category

Tutorials

Magic With MotionLayout

Ladies and gentlemen, if you have not checked out ConstraintLayout 2.0, you are missing out.  I have been playing around with it and I’m at the point of no return. Ever wanted to make cool animations? Well, it’s a walk in the park. You just need to know where the park is and how big it is. 😏

About ConstraintLayout

ConstraintLayout 2.0 was announced at Google I/O 2018. What got me excited was MotionLayout, a tool for layout animations. Yes, you read that right. Layout Animations. In this series well take a look at how we can use motion layout to create a Twitter Profile like UI.

Twitter Profile Ui build with motion layout
MotionLayout in action

 

Yap… All this done using XML. 😃I’d recommend that you check out this introduction by Nicolas Roard.

Intro

Here’s a break down:

  • Adding ConstraintLayout 2.0 & MotionLayout
  • Motion Layout
  • MotionScene
  • OnSwipe
  • Transition
  • ConstraintSets
  • KeyFrames
  • Conclusion

Adding MotionLayout

To add motion layout to your project, simply add the following to your gradle file:  

MotionLayout

As the name says, it’s Motion + Layout files. Motion layout builds upon ConstraintLayout. It allows us to handle layout transitions and complex motion. Think of it this way, ConstraintLayout allows us to create complex layouts and MotionLayout is the icing on the cake adding animations to the layout.

Fast forward creating the layout….

Voila ...

ConstraintLayout

Something to take note of, MotionLayout is a subclass of ConstraintLayout. So we need to make sure our root tag is MotionLayout.

MotionScene

We’ll a separate XML file inside res/xml that will contain MotionLayout information then we will reference the file in out activity file like so. 

app:layoutDescription="@xml/scene_twitter_profile"

The MotionScene contains the animation magic.

Transition

We’ll start by checking out the Transition Element. This defines what the start and end states are. We define the states using the respective attributes: constraintSetEnd and constraintSetStart. The ids of the states can be anything,thesame way we name views.

OnSwipe

OnSwipe is contained inside the Transition definition. It lets you manage the transition by matching the motion of the users finger.  There are 3 main params:

  • dragDirection: Think of this as the scroll direction (top / bottom /  left / right ). 
  • touchAnchorId: This is the view we are tracking, in our case it will be the RecylerView. When the user scrolls up or down (dragDirection) do some magic
  • touchAnchorSide: the side of the object that should track your finger (right /left /bottom /top)

This is how it looks

We are almost there… Stay with me. 🤓

ConstraintSet

We will use ConstraintSets to handle our states. To do so, we will create two ConstraintSets or should I say we’ll create a set. 😏No? Fine…

We can now add constraints for the views in the layout file. You will notice that it looks like a normal file just that we don’t specify the widget.

With only those lines of code, we get the following effect. We are not there yet but this is progress. We need to fix a couple of things but before we do that, let’s see what’s happening. 

There are a 3 things to take note of:

  1. Attributes Override: Defined attributes in the scene file will override those in the layout file. ( layout_height, padding, margin, constraints …) So you can actually get rid of them in the layout file making it cleaner. I really like this.
  2. ConstraintSet values: If you take a closer look at the layout height, you’ll see there’s a difference. The first one defines the size of the image in its original state (expanded) and the second one in its final state (collapsed). This gives us a collapsing bar effect.
  3. CustomAttributes: We have access to various attributes that allow us to modify a widget. In this tutorial, we are using imageAlpha to modify the transparency of the image. You can read more about CustomAttributes here.

Image Fix

When we scroll up, we want the image to scroll under the toolbar. To do this we simply change the elevation of the toolbar in the final state (collapsed). We update it from 2dp to 4dp. JUST that and ….

KeyFrameSet

Before we wrap this up, I’ll touch on KeyFrameSets. They let us change a widget at a certain point during the transition. In our case, we want to shrink the profile image when scrolling up and down.

The KeyFrameSet contains KeyAttribute. We framePosition to specify when we want to modify the image. It takes in a value between 0-100. In our case, when we are 20% into the transition, start to scale down the image. 

Still on KeyFrames, we want the UserName and tweet count to appear on the toolbar. We’ll update the alpha value of the TextViews to “1” when we are 100% into the transition. This will make them visible since we’ve set the widgets to invisible by default.

Final Result

After patching it all up, we get this:

Conclusion

You can see how MotionLayout is amazing and powerful. No Java/Kolin code was used. Let that sink in. 

It goes to show the power of MotionLayout. I’m really looking forward to the UI editor and other amazing updates.

The source code for this article is available on Github

Resources

  1. Build a Responsive UI with ConstraintLayout
  2. Android Fundaments: ConstraintLayout by Rebecca Franks
  3. ConstraintLayout CodeLab

The source code for this article is available on Github

Android Architecture Components Part 2 – Dependency Injection

As promised, part two is here. ? Before we get our hands dirty, let’s do a quick recap. In the previous post, we created a simple app that displays a list of user names using Android architecture components library. We divided our app into the following layers for better code responsibility and separation of concerns:

  1. View/UI layer
  2. ViewModel layer

This worked pretty well but our data was hard coded. In this series, we will setup Retrofit for API Calls & Dagger 2 to add Dependency Injection to our app and use TMDB API to get some data. With that said, our new architecture will look like below.

Picture from: Android developers site

Before We Begin …

Who the hell is Dagger and what is Dependency Injection? Worry not we will walk through this first. So let’s define some terms.

Dependency: This is when a  class has a dependency on another class, if it uses an instance of this class. We call this a _class dependency.

Dependency Injection: Also known as DI. Dependency Injection is a technique whereby one object supplies the dependencies of another object. This means an object creating its dependendencies via new operator is strictly prohibited.

We will be using Dagger 2 for DI.

Dagger Annotations

Dagger 2 uses the following annotations:

  • @Moduleand @Provides: define classes and methods which provide dependencies.
  • @Inject: request dependencies. Can be used on a constructor, a field, or a method.
  • @Component: enable selected modules and used for performing dependency injection
  • @Singleton : annotation ensures the class instance as singleton across the dependency graph.

Dependency Injection can be a beast and I don’t want to dive into it. There are a couple of articles that talk about this. I’ll add them at the end of the article. ?

Project Structure

For some organization, We’ll handle injection in a package called di.

Let’s Code

The source code is available on Github.

You’ll need to add dagger dependencies to your build.gradle file

Creating Modules

We’ll set up a couple of module classes.

  1. App Module: This will ensure that TmdbService will be a singleton throughout our app.
  2. NetworkModule: This helps us setup retrofit and logging.
  3. ViewModelModule: Module to set up our viewmodels.

Let’s set up our modules:

NetworkModule.

We’ve done a couple of things in the NetworkModule that I think are work taking note of

  • provideOkHttpInterceptors(): Sets up HTTP logging. This will allow us to monitor network requests and responses. It will only log when running the Debug version.
  • okHttpClient(): Sets up OkHttp client with some custom configs.e.g Adding HTTP logger, set timeout & read duration and custom interceptor that adds TMDB API key to requests.
  • provideRetrofitClient() : Sets up Retrofit client.

AppModule

Now that we have the Network module created, we can create an app module that will now ensure we have a singleton for our API service interface. If you’ve not used Retrofit, the interface defines API endpoints. It simply looks like this.

Here’s how the NetworkModule looks like. We’ve added the NetworkModule and ViewModelModule to the AppModule.

Note:
The method names for the providers, such as provideTmdbService()provideRetrofitClient(), are not important and can be named anything you like. Dagger only looks at the return type.

Create Components

We only have one component at the moment AppComponent.

We’ve specified the modules we want to be used with the component inside the @Component annotation.

Boom. We are done setting up our dagger. ?

Let The @Injection Begin

Now that we have all our dependencies set up, let’s use them.

1. Application Class

We need to initialize the dependency graph for our application by using the Component. This is pretty simple in Dagger 2.

AppInjector.init(this);

Don’t forget to add property android:name=".TmdbApp" to the tag in AndroidManifest.xml file.

2. TmdbRepository Class

I’ve created a class TmdbRepository in the repository package that is responsible for making API requests and returning data to our ViewModels.

We’ve used @Inject annotation on TmdbRepository constructor which in turn tells Dagger that to use the constructor to create an instance of TmdbService. This adds this class to the Dependency Graph.

3. MainActivityViewModel Class

As discussed earlier, using @Inject annotation on MainActivityViewModel constructor which in turn tells Dagger that to use the constructor to create an instance of TmdbRepository.

By doing so, the ViewModel does not care how we get out data. It just wants data from our repository.

4. ProjectViewModelFactory Class

ProjectViewModelFactory implements ViewModelProvider.Factory. This class is responsible for instantiating our ViewModel classes.

5. MainActivity Class

We can now use load data in our MainActivity. We call getPopularMovies() which will return some data. We then use observe which will listen for any changes to our data.

This is how the entire code looks like.

Wrapping it up

You can download the final project on Github

Dagger can be a bit of a pain when starting but don’t let it get to you. Dependency injection becomes useful when implementing proper testing into your app, allowing mock implementations of back-end APIs and data repositories to be used in testing.

There’s much more to learn about in Dagger 2 and its usage, including:

  • Scopes
  • Subcomponents
  • Testing with Mockito

In the next series, well look at setting up the UI and maybe writing some tests. In the meantime, happy injecting.

References

  1. Vogella – Dependency  Injection
  2. YouTube video by Gregory Kick: DAGGER 2 – A New Type of dependency injection
  3. YouTube video on DI by Dan Lew: Dependency Injection made simple
  4. Dagger 2: official page
  5. Codepath: tutorial on Dagger 2