You know those BottomNavigationView’s that are more commonplace in Android apps these days?
Recently, I’ve been building a small sample app for a PluralSight course I’m working on that has one of these BottomNavigationView’s and it wasn’t apparently obvious to me how I should be switching the actual views that are on screen as the user taps through various items in the bottom menu. A simple Google search didn’t answer my question either since most blog posts and StackOverflow answers on the subject matter did one of the following:
Simply introduced the BottomNavigationView and left it at that
Switched the views using a ViewPager but when I downloaded the sample app, the effect seemed a bit weird
Recommended starting up an entire Activity every time a user tapped on a new menu item, but I didn’t like that since that meant you had to re-inflate the bottom navigation view every time. Also, when I implemented it that way, there seemed to be a bit of a lag every time I tapped on a new item.
Thus, I decided to implement the switching of BottomNavigationView menu items by inflating appropriate Fragments into the view. And now… let’s go over the code on how to implement this 🙂
These two layout files and the menu item xml file will give us a screen that looks something like this.
Now, what we want to implement is the actual switching of the screen in display. The screen in-display is actually the fragment that is inflated from the MainActivity. Also, when the user taps on a bottom menu item, we want the appropriate fragment to take place of the previous fragment. Here’s how we do it.
In the code, you can see that I inflate a new HomeFragment, which is the default fragment in my code sample automatically, which I store into a mCurrentFragment variable. And based on what the user taps on the BottomNavigationView (which I have a listener set on), I store the appropriate newly instantiated fragment to the mCurrentFragment variable and display that fragment instead.
So far, this is the simplest and most modular way I could think of to get this working. Google docs didn’t seem to have recommended approaches, and blog posts online didn’t have solutions that I liked. The solution that seemed to give the most fluidity that didn’t use fragments like I do involved simply hiding and then displaying certain elements in the layout file depending on which menu item was active. I didn’t like this since that meant unnecessary code will have to be run all at once, potentially causing memory problems.
I recently had to resolve a bug in one of my projects where if the user pressed the back button in the Toolbar to go back to the previous screen, the app would crash.
And the app would crash because the previous screen was supposed to be displaying a data that was passed from the screen before that, and the activity would for some reason lose reference to the variable that was supposed to represent that data. To illustrate what I was experiencing, the flow went something like this.
Screen A -> Screen B -> Screen C
Let’s say the app is a cupcake ordering app. Screen A displays a list of cupcakes. User clicks on one cupcake and we display the single cupcake in Screen B. User clicks “Order Cupcake” which takes the user to Screen C. The user decides he/she does not want the cupcake and presses the back icon in the Toolbar.
Note: the bug does not occur if the user presses the Android’s native back button, the one on the bottom of the phone that’s native to the OS.
Once the user clicks the back icon in the Toolbar, the variable that represents the cupcake in Screen B will become null and it would cause the dreaded NullPointerException.
And the code in Screen B looked something like this.
Why is the launchMode option so important? It turns out that the standard launchMode (meaning if you don’t put one in), causes Android to always recreates the activity (calling onCreate) even if the task stack (parentActivityName declaration) is handled correctly. To prevent this, you need to add the launchMode="singleTop" declaration to your activities.
For some reason, I think the default configuration should be to have the launchMode set to singleTop when the user presses back into the previous activity, rather than recreating the activity entirely. I can’t think of a single app that I use where I expect pressing the back button on the Toolbar to behave differently than when I press the Android OS’s back button.
In this blog post, we’ll go over how to build out custom Info Windows in Android.
What are Info Windows? In applications that display a list of locations in a map with pins, you can often tap on the pins to display information about that specific location. One example is the maps feature in the Yelp app where the app will display a map with various pins of locations of interest on the map. You can click on the pins and it’ll display a little pop up with the various data about that location. Sample screenshot is below.
That little pop up that displays with the label “El Gran Pollo”, rating table, and etc is the Info Window. The Android SDK comes with a standard InfoWindow that allows you to display a title and description. If that’s enough and the design of the standard InfoWindow meets your requirements, then you can stop here. If you need to customize your InfoWindow, continue reading.
This tutorial is going to assume that you know how to integrate Google Maps into your Android application and that you know how to obtain location information using the LocationListener and GoogleApiClient.
Set those up first and prepare a list of data that you would like to display.
Sample data that we’ll be working with
We’ll be displaying different restaurants on the map. The model will look like
The name and description fields are straightforward. photoUrl field will return a url with an image file. We’ll be using Picasso to insert photos into the ImageView‘s.
Pin the markers
Assuming that your Google Map on your Activity (or Fragment) is set up and ready to go, we’ll start pinning the markers. We’ll have a list of Restaurants in an ArrayList and go from there.
// This is a bit of a hack to get custom images loading. If you
// don't have images in your custom info windows, you do not need
// the following two lines
The code above is simple but there are two non-obvious things. The first is the mRestaurantMap where we keep reference to the restaurants themselves with the markers as keys and the second is the last two lines of code where I call showInfoWindow and hideInfoWindow methods on the markers.
In the RestaurantInfoAdapter that we’ll be coding up next, we’ll need to be able to retrieve the correct restaurants that belong to a specific marker that the user taps on the screen. the mRestaurantMap HashMap is an easy way for us to store and retrieve the correct restaurants.
As for the showInfoWindow and hideInfoWindow methods, this is a workaround in order to display any images that you want to show on your Info Windows. As noted in the comments in the code snippet above, you do not need these two lines of code if you do not have any images in your custom info windows.
Write the InfoAdapter
Let’s write our Custom Info Adapter and the accompanying XML layout file.
First create your custom layout file. I’ll be naming the file info_window_restaurant. The code for the layout is below.
In this layout, I’m using a CardView in order to easily provide rounding border radius. If that’s not a requirement for you, then you can use whatever layout (RelativeLayout, LinearLayout, etc.) that you want. I also have an ImageView in there to display the photo of the restaurants that will come in later.
Next up, let’s build our Info Adapter. Back in your Activity or Fragment file where you had that pinMarker method, add this class.
Here, you can see the mRestaurantMap coming into play, where we take the marker that is passed in to retrieve the correct Restaurant from mRestaurantMap. Then we grab that and set the texts and images for the TextView‘s and the ImageView.
If you are observant, you may have noticed the new MarkerCallback(marker) line in the Picasso part of the getInfoWindow method. This is a workaround that we have to do specifically when trying to load images in custom info windows due to the race condition that occur between Picasso and Google Maps. This StackOverflow post’s accepted answer explains it pretty well.
Basically, you’ll need to build a custom callback into Picasso or your image loading in your custom info windows will be inconsistent at best and non-functional at worst. Also, I found the code solution in that StackOverflow post to not work for me, so without further ado, below is the solution that have worked for me.
And yep, the solution is pretty much the same, except that I call hideInfoWindow before showInfoWindow. I found that just calling showInfoWindow doesn’t help reload the page.
Also, remember the two lines of code in the pinMarkers method where I call hideInfoWindow and showInfoWindow during the pin marking process? The reason I do that is because if I don’t, the image in the first pin that the user taps on, the image will never load. I’m not sure why, but hiding and showing the info windows quickly (so that the user doesn’t notice) when you’re pinning the markers initially is a workaround that I found to work well.
You can also further optimize this solution by adding a boolean variable in your RestaurantInfoAdapter to determine whether Picasso has already loaded and displayed the image or not. Since Picasso automatically caches images for you, if the marker has been tapped and image already loaded and displayed, we do not have to add the MarkerCallback into our Picasso calls. This is simple to do so I won’t display that here.
I hope this post helps anyone who needs to build custom info windows in their Android apps.
Sometimes, you’ll need to get one or a list of nearby addresses using latitude and longitude. Unfortunately, the standard way of implementing this feature has a bug within Google’s Android ecosystem, making the implementation unreliable. I’ll go over an alternative implementation that is more reliable.
Let’s say that you want to retrieve an address using the latitude and longitude that you get from your phone’s GPS system. The standard documented way of going about this is using the Geocoder library, pass in your latitude and longitude data, and ask for a maximum number of suggested addresses. The code usually looks something like this.
This is the ideal and clean way to retrieve addresses using geolocation data, but the results you get will be inconsistent. More often than not, you won’t get any addresses back and you’ll get an error in your console that goes something like Geocoder throwing exception: IOException: Service not Available.
If you look at the Geocoderdocs, it has a line that says
The Geocoder query methods will return an empty list if there no backend service in the platform. Use the isPresent() method to determine whether a Geocoder implementation exists.
The question is… what the heck is a “backend service” mean? Just like many of Google’s lovely documentation, it fails to mention what this backend service is. Is it something provided by Google or is it something you have to implement on your server side code? At the time of this writing, I still don’t know the answer.
Many of the solutions to this problem found on StackOverflow suggests that you simply reboot your device. This seems to work for some people (it never worked for me), but this is an unreasonable request to ask of to your users. Thus, I came up with something way more roundabout to get the addresses but way more reliable at the same time. Rather than using the Geocoder library, I make http requests directly to Google Maps API with the latitude and longitude interpolated in the web url. I get a JSON object back from this request and I parse through that JSON object to get the address information that I need.
The code sample below assumes that you’re using OkHttp version 3 to make your HTTP requests and Google’s gson library to parse the JSON, but you can use whatever you want.
As you can see, the code is straightforward. I build a url string that has my latitude and longitude information in it, and I make a HTTP request to that url, and then I parse through the JSON object that I get back appropriately to get the address that I want. The nice part of the JSON object that we do get back is that it comes with a field with the address already properly formatted for us 🙂
There are other “workarounds” that utilizes Geocoder floating around the internets (some of which include trying to make requests with Geocoder in an endless while loop) and using Geocoder ends up in cleaner code, I think that the brittleness of that library makes it a suboptimal solution. My workaround makes you write a bit more custom code to get the address data that you need, but it’s reliable and will work consistently.
A lot of apps have a landing screen with images and logos where you can slide through various screens. There are various third party libraries in the open source world that makes this easy, but none of them are highly customizable. In this post, I’ll go over how to build one of these slideshows from scratch.
Just so that we’re on the same page, an example library that lets you easily build an Intro Slider is https://github.com/apl-devs/AppIntro. In one of the apps I’m working on, I had to build out something similar, but with two static buttons in the bottom of the page that the user can interact with. Needless to say, none of the libraries I could find was able to accommodate this. So, I had to build my own.
And here’s the video of the intro slider that we’ll be building
1 – Define the slider position dots and various colors
Open your colors.xml and define two colors for our slider dots, one for an inactive state and one for an active state. Also, go ahead and define a color for the white color and colors for the three background images that we’ll have. These colors will come into play later.
<!--Bunch of other color definitions up here-->
<!--Slider dot colors-->
<!--Slider Background Images-->
You can change those color definitions to however you want them.
2 – Remove the Toolbar and then hide the notification bar in MainActivity
We want to remove the Toolbar that comes with the standard MainActivity and then hide the notification bar to give more prominence to our intro slider.
For removing the Toolbar, we need to add two style definitions to our AppTheme. So open up styles.xml and then add these two lines into your main app theme.
Adding those two lines with the windowActionBar and windowNoTitle will set an application wide theme where the Toolbar (or ActionBar for those of you who want to proper naming) will be hidden by default.
Now, we want to hide the notification bar. This has to be done in code and isn’t available in all versions of Android. Open up your MainActivity file (or whatever activity you are displaying your intro sliders) and add this code.
Make sure you add those two lines before you call setContentView. We want it to take effect before we set the view of the activity. What this will do is hide the notification bar if the feature is available on the device running the app (SDK version of the device is higher than 21).
3 – Creating the slides
We want to create the 3 slides that the user will be able to swipe through (you can create more if the app you’re building requires more slides). Under your res/layouts folder, create three layout files named landing_slide_1.xml, landing_slide_2.xml, and landing_slide_3.xml respectively.
All of the slides are practically the same with the exception of the texts and the background colors that we’re displaying. This is to distinguish the slides from each other so that you will be able to see that different slides are displaying as you are swiping through the ViewPager that we’ll be building. You can also replace the texts with ImageViews and other components as you see fit.
4 – Build the MainActivity XML layout
We want the above landing slide layout files to display in our activity_main layout file. We also want them to be displayed inside a ViewPager. Finally, we want to have two static buttons at the bottom that stay in place as the user swipes through. Open up your activity_main.xml file and copy/paste this in.
I’ll go over the important parts of this code step by step.
First important parts are the mLayouts array containing various layout ids and the addBottomDots method. The mLayouts integer array holds all of the layout files that you’ll be displaying in your intro app slider. In our case, we have three: landing_slide_1, landing_slide_2, and landing_slide_3. We then have our addBottomDots method that will programmatically add the slider dots to our layout file. These dots will help indicate to the user exactly which slide he/she is in.
When we are defining these in our onCreate method, we want to pass in “0” into our addBottomDots method so that when the user first opens the app, the first dot will be highlighted. In our addBottomDots method, you can see at the bottom of the method that we retrieve the current dot with the currentPage integer passed in to set the text color of that dot to R.color.dot_slider_active that we defined in our color definitions at the beginning of this tutorial.
The sole reason for us to even have this OnPageChangeListener is to call the addBottomDots method with our current position so that the correct dot is highlighted as the user swipes through the various slides. As you can see, we call our addBottomDots method in the overridden onPageSelected method, passing in the current position of the ViewPager page. This will dynamically activate the correct dot and inactivate the rest of the dots with appropriate colors as the user swipes through the various landing screens.
Second piece of code that we need to write is our ViewPagerAdapter. We define it as SliderViewPagerAdapter in our sample app and it extends itself from the PagerAdapter class. This part of the code is pretty simple. The adapter determines which view to inflate using the mLayouts array we defined above (the one that contains the various layout ids).
After all this, we finish setting up our MainActivity by setting an instance of our SliderViewPagerAdapter to our ViewPager and then setting our viewPagerPageChangeListener as our ViewPager’s OnPageChangeListener.
This post will show how to filter through a list of data that’s set in a RecyclerView.
A lot of apps have a search feature where you have a list in a RecyclerView and a Search menu bar where as the user types, the list filters automatically. I wrote a whole post on how to build a custom search view in one of my posts. Thankfully, this guide will be more brief and straightforward.
The main library that we’ll be utilizing is the same SearchView library that we used in my Custom SearchView post, MaterialSearchView.
If you’re observant, you’ll see that we call two methods sequentially, getFilter and filter on my RecyclerView.Adapter (variable named mAdapter). We have a method on my adapter called setData and we use that to set our data. I’ll go over the getFilter and filter methods first.
getFilter && filter
First thing we want to do is to implement Filterable on our RecyclerView.Adapter
// More typical RecyclerView stuff below, like ViewHolder pattern and stuff
There are a few things going on here. First, we implement Filterable to our adapter and implement the necessary methods getFilter and getFilteredResults. What these two basically do is take in a string (which is passed in from our activity which is bound to the user inputs in our SearchView), and filters through the data list. It scopes down the data based on the filtering conditions we give it, and returns the result. This implements the actual filtering feature that works with the filter method we have in our mAdapter.getFilter().filter(newText) method chain.
One important thing that we do in our activity though is when the user input is empty. If you look at the listeners that I set on our SearchView, you’ll see that I constantly set the dataset in our RecyclerView back with the full data set. The reason for this is because the data set in our adapter will be reduced as the user searches through. Thus, we want to “reset” our list of data back up to full when the user either deletes some of his/her input to search for something else or clears the input in the SearchView entirely.
SVGs (Scalable Vector Graphics) are awesome. They resize themselves perfectly to any size without quality loss and thus allowing us to skip the tedious process of scale the image files for different density buckets.
In web development, we can use SVGs directly for improved front end performance. Unfortunately in Android development, we cannot use SVGs directly and need to convert them to their corresponding XML files. Doing this is used to be a tedious process (I think I remember doing this in web development, cobbling together various tools on the web), but Android Studio includes a tool called Vector Asset Studio to make this process easier.
Here are the steps to integrate your own SVGs into your Android app using Android Studio.
Right click on your drawable folder in Android Studio and then drill down to New -> and then select “Vector Asset”.
Do note that Android Studio comes with all of the SVG Material Design icons that you can export into appropriate XML formats. But in our case, we want to use our own SVG files, so select “Local file (SVG, PSD)” under Asset Type and choose the appropriate file under the Path section. Once you have selected your file, click “Finish”.
And that’s pretty much it. Clicking on that “Finish” button will create a new XML file that will be a representation of your SVG file under your drawable folder.
There’s a method called onBackPressed that you can override in Activity classes. This is a pretty easy way implement any custom action you might want to take if and when the user presses the back button. However, this onBackPressed override option is unavailable in fragments. We can make this feature available in fragments however. And that’s what I’ll be going over in this post.
Our activity and fragment that we’ll be referring to as examples will be called MainActivity and MainFragment (creative names, I know). MainActivity will be displaying MainFragment and for whatever reason, we want to be able to listen to onBackPressed in our fragment instead of our activity. Just as a note, I had come across this problem where one activity had a ViewPager displaying content from two different fragments and I had to listen to the back pressed action in the fragments instead of the Activity due to the requirement of passing some data from individual fragments instead of the Activity.
To implement this, we need to utilize interfaces in our Activity which we will implement in our Fragment. So, in your MainActivity, add an interface called OnBackPressedListener like this and override both the onDestroy and onBackPressed method as shown.
Here, we are defining an interface called onBackPressedListener which defines a method called doBack. We will be implementing this interface in our fragment. We also have a method called setOnBackPressedListener which we will be calling in our fragment.
We are also overriding both the onDestroy methods and the onBackPressed methods. In the onDestroy method, we are nullifying the instantiated onBackPressedListener so that it doesn’t interfere with any new future activities that are instantiated. In the overriden onBackPressed method, we call the doBack method on the onBackPressedListener if it is not null, or just call the normal onBackPressed method of the Activity if it is null. We’ll be utilizing this altogether in our fragment.
Now, implement our fragment like this. The main thing you’ll see is that we’ll be implementing the MainActivity’s OnBackPressedListener in our fragment.
// Whatever you need to do here when the user presses back
The most important part in our MainFragment is that we implement the OnBackPressedListener interface of our MainActivity and then in our onViewCreated method that we override, call the setOnBackPressedListener method while passing in the MainFragment. This will allow us to utilize MainActivity’s onBackPressed method in the doBack method of our MainFragment.
And that’s how you can listen for the back pressed action within your fragments. Sometimes I do wish that Google would just provide default APIs for these types of things.
Bottom Navigation View was added to the version 25 Android Design Support Library awhile ago. This makes it easy to add those bottom navigation menus that were previously more prevalent in iOS apps.
Previously, Android apps that adhered to the Material Design guidelines generally used the Drawer to navigate between menus. Some time last year, the Bottom Navigation View has been added as part of the Android Design Support Library to make it easy for developers to add the bottom menu bars. Before, it was an uphill battle to try to add these bottom navigation menu bars. Now, it’s super easy. By the Bottom Navigation View, I’m referring to something that looks like this.
One thing that I love about these Bottom Navigation Views is that I can easily navigate through different sections of the app while using my phone one-handed. My hands aren’t very big, and phones these days tend to be on the bigger side, so I’ve noticed that if the app I’m using uses that navigation drawer that activates via the hamburger menu bar that sits on the top left of the app, I can’t use the app one-handed. Perhaps that’s why the Android team made the Bottom Navigation View as part of the Support Library? Who knows.
While the library works great, I have come across one issue when I was using the Bottom Navigation View on one of my client projects. If there are more than 3 items in the menu bar, then there are animations that cannot be easily removed. Also, if there are more than 3 items, the currently selected item is more pronounced on the screen. Here’s an example of what the default Bottom Navigation View looks like with more than 3 items.
You see how the spacing between items are uneven and the actively selected menu item is more pronounced? If this is what your design calls for, then I guess this is fine. But the client project I’m working on right now needs more than 3 items in the Bottom Navigation View and needs the spacing between the items to be even, regardless of the activeness of the currently selected menu item. Also, I kind of think the unevenness between the 4 menu items look ugly.
Unfortunately, the BottomNavigationView library from Google doesn’t give you a straightforward way to remove this unevenness and the default animations that come with the library if you have more than 3 items. There is one answer on StackOverflow here but the accepted answer looks like an overly complicated workaround for something that seems simple. Also, I tried the accepted solution and it has some issues with the color of the actively selected menu.
For now, the best solution to have an easier and tighter control over the bottom navigation view is to use a third party library. There are many out there but the one I ended up choosing for one of my current client projects is called BottomNavigationViewEx. I picked this one because it simply extends the current BottomNavigationView library straight from Google and sprinkles on extra features.
With this library, to remove the unevenness and the default animations, all you have to do is call one line method on your BottomNavigation View like this.
Much cleaner than writing that helper class suggested in that StackOverflow answer right?
Of course there’s a downside to be relying on a third party library for a small issue like this, and I’m pretty sure Google will add these features over time to their native BottomNavigationView library. But for now, I think this is an acceptable solution to have your own pretty Bottom Navigation View. Also, since it’s only a one liner, when Google eventually does add this feature natively, all you would have to do is simply swap out the libraries and replace that one line with something else, which will probably be another one-liner from Google.
Android development is weird in that Google gives you all these guidelines that we developers and designers should follow like the Material Design , but doesn’t provide the tools necessary for us to easily implement these designs.
The Android Chip is one material design component that Google doesn’t provide an easy way to implement. Yeah, those chips with the profile photo and the user’s name/email that you might see in the Gmail app and other apps that follow the Material Design guidelines.
Ideally, the Android SDK should provide an easy to use support library and a View so that we can implement these chips within a few minutes. Something like this will make me happy.
Unfortunately we have to implement our own. There have been attempts by third party libraries to solve this Chip problem but all of them expect a certain layout and requirements. Thus, they are not very flexible. To have a flexible Chip, we need to implement our own.
So… just like many of my other posts where I try to make other Android developer’s lives easier, I’ll just copy and paste the chip layout that I’ve built and use whenever I need to use a chip. Keep in mind that this layout needs some sort of library for Circular Image Views. I like to use this one https://github.com/hdodenhof/CircleImageView
At any rate, the code is below for building out a Chips layout that you can include and reuse anywhere throughout your codebase.