How We Developed Jelly ToolBar Animation for Android in Kotlin

You don’t have to spend much time looking for a search button in a mobile app. The majority of apps have a magnifying glass icon on the right side of the navigation bar. This icon always looks the same and acts the same: you click on the magnifying glass and the search field opens up.

Such a standard UI element as a search bar isn’t typically a designer’s favorite spot to apply their animation creativity. But who said we shouldn’t?

We thought, “What if a regular search field could tremble while opening up?” When we saw the final result of our search bar animation it reminded us of jelly – that sweet, clear substance made from fruit juice and sugar boiled to a thick consistency.

It looks tasty, doesn’t it? Let’s see how we implemented this jelly toolbar animation for Android.

JellyToolbar animation for Android

How we implemented Jelly Toolbar animation

The jelly toolbar animation looks pretty simple, and for the most part it is. We created a custom view that contains the well-known toolbar, a view containing the background, and a view containing icons. The structure looks like this:

<FrameLayout >
   < />
   <com.yalantis.jellytoolbar.widget.JellyView />
   <com.yalantis.jellytoolbar.widget.ContentLayout />

How does the JellyView work?

We decided to draw the animation on Canvas. Before showing you a piece of our Kotlin animation source code, we’d like to describe the main idea behind our implementation. To produce the bouncing of the view, we used a quadratic Bezier curve. (You might also want to check out our article about drawing Bezier curves.)   

The shape of this curve changes depending on the position of the control point. Let’s look at how we draw the view:

override fun onDraw(canvas: Canvas?) {

  private fun redraw(canvas: Canvas?) {
       paint.shader = gradient
       path.apply {
           moveTo(jellyViewWidth, 0f)
           lineTo(width.toFloat(), 0f)
           lineTo(width.toFloat(), height.toFloat())
           lineTo(jellyViewWidth, height.toFloat())
           quadTo(jellyViewWidth - difference, height / 2f, jellyViewWidth, 0f)
       canvas?.drawPath(path, paint)

The value of the difference variable changes the control point of the quadratic Bezier curve. To change the value of the control point we created a custom interpolator. The sine function properly represents the bouncing of a jelly-like object:

class JellyInterpolator : Interpolator {
   override fun getInterpolation(t: Float) = (Math.min(1.0, Math.sin(28 * t - 6.16) / (5 * t - 1.1))).toFloat()


How to use this library in your project

First, add JellyToolbar to the xml layout of your activity so it looks like this:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android=""

       app:titleTextColor="@android:color/white" />


Next, pass an instance of the JellyListener and content view (the view that will be inserted into the toolbar) to the JellyToolbar. As you can see, JellyToolbar has the getToolbar() method to let you use all the methods of the standard Toolbar.

public class MainActivity extends AppCompatActivity {
   private JellyToolbar toolbar;
   private AppCompatEditText editText;

   protected void onCreate(Bundle savedInstanceState) {

       toolbar = (JellyToolbar) findViewById(;

       editText = (AppCompatEditText) LayoutInflater.from(this).inflate(R.layout.edit_text, null);

   private JellyListener jellyListener = new JellyListener() {
       public void onCancelIconClicked() {
           if (TextUtils.isEmpty(editText.getText())) {
           } else {

To control the animation flow, use the collapse() and expand() methods.

You can find this library and many more in our GitHub repository, and can check out our designs on Dribbble:



4.2/ 5.0
Article rating
Remember those Facebook reactions? Well, we aren't Facebook but we love reactions too. They can give us valuable insights on how to improve what we're doing. Would you tell us how you feel about this article?

We use cookies to personalize our service and to improve your experience on the website and its subdomains. We also use this information for analytics.