** This article has been ported over from my Medium blog. - Original time of writing: Feb 3, 2017 **
Introduction
I was requested to create an Android UI, which would be the front-end for a multi-band graphical equalizer. Turns out that flipping a SeekBar over is not as evidential as you’d initially suspect.
Our first and most obvious candidate was h6ah4i’s android-verticalseekbar library. After implementing it and finishing up my design in Android Studio, I soon after noticed that the actual result on the phone didn’t match the result Android Studio showed me. And then after screwing around with padding, margins, whatever I could think off, I decided to drop the library. For some reason the VerticalSeekBarWrapper kept clipping off a part of the VerticalSeekBar thumb which caused the thumb to actually disappear once the VerticalSeekBar was set to its maximum value.
So that’s when I decided to look around for existing solutions once more before actually creating my own implementation, which didn’t sound all that interesting to me considering I had a deadline ahead and I’ve never been much of a UI/UX kind of guy. Don’t reinvent the wheel if you don’t plan on learning more about wheels.
After digging through a plethora of StackOverflow questions and answers, I finally stumbled into an interesting piece of code in the AOSP. The SeekBarRotator is nothing more than a ViewGroup that just flips it’s child by 90°, and it’s just the thing that I needed! So after importing the Java-file and necessary license/notice files, I was ready to start creating the EQ. Now let’s dive into the actual code.
Creating the VerticalSeekBar
Notice: This example project is going to be extremely rudimentary and its only purpose is to show how to implement the SeekBar.
Before we start creating the UI, let’s import the SeekBarRotator into our project.
Once the SeekBarRotator is available in our codebase, we can start using it for our UI. Open up your target xml file and insert the SeekBarRotator as a container, and give it a normal SeekBar as a child.
Normally the result should look like something in the lines of this, depending on your UI specs:
Looking at Android Studio’s Layout Editor, we get the following result:
If you need to reuse this structure a lot, don’t hesitate to make a wrapper component called VerticalSeekBar to ease up the development.
So there you go, whoever was searching for a basic vertical SeekBar, you’ve now found it. But whoever also needs the double tap function, stick with me a bit longer.
Creating the Double Tap function
To give a little background on ‘why’ I needed the double tap function, it’s simply because the client wanted to be able to reset the SeekBar to default (0dB) in an intuitive manner. Many DAW’s allow you to reset a fader to default by double clicking the control, and this would be our way of sticking to that paradigm/UX.
Considering we want to stay as close to the default SeekBar functionality as possible, we’re going to use it as a base-class and extend upon it. So let’s go ahead and create our own DoubleTapSeekBar class:
Good start, but now we need to implement the additional logic. Now luckily for us, Android has already provided a SimpleOnGestureListener which you can use to define custom behaviour for events such as OnDown, OnLongPress, OnDoubleTap, OnFling, etc…
We are going to implement this class in our DoubleTapSeekBar to allow us to override the OnDoubleTap event. This implementation looks as follows:
What we’ve done here, is basically extending upon the default SimpleOnGestureListener class, overriding the onDoubleTap method and instantiating it in our DoubleTapSeekBar constructor as a private, global reference. Afterward we have to override the SeekBar’s default onTouchEvent method to make sure that we also trigger our custom defined behaviour.
So this result is already pretty cool, but we want to be able to define the behaviour outside of the component. To achieve this, we will create an extra interface class called DoubleTapSeekBarEvent:
We’ll pass the DoubleTapSeekBar as a parameter so we have access to it’s API. If you played around with the DoubleTapSeekBar a bit and tried to set it’s progress to getMax()/2 using onDoubleTap, you have noticed that the DoubleTapSeekBar actually doesn’t get set to the center of the SeekBar, because it needs to get debounced to work properly for this application. We’ll implement some debouncing using a rough blocking technique with a TimerTask.
After implementing all of these features, we come to this final result for the DoubleTapSeekBar and the Activity:
Outro
That’s all folks. If you want to take a look at the final project, please have a look at the demo repository here: VerticalDoubleTapSeekBar
Comments