Springy heads


Feb 17, 2015
Feb 21, 2018 (Retired)
Flipkart Incubator (flipkart-incubator)
Prempal Singh (prempalsingh)
Kiran Kumar (thekirankumar)
Vivek Soneja (viveksoneja28)
Source code

THIS PROJECT IS NO MORE MAINTAINED. A good alternative is at https://github.com/google/hover

Springy heads

A chat head library for use within your apps. This includes all the UI physics and spring animations which drive multi user chat behaviour and toggling between maximized, minimized and circular arrangements.


You can also download the demo app



compile 'com.flipkart.springyheads:library:0.9.6'

How to use

Define the view group in your layout file


Then define the view adapter in your activity

final ChatHeadContainer chatContainer = (ChatHeadContainer) findViewById(R.id.chat_container);
chatContainer.setViewAdapter(new ChatHeadViewAdapter() {
    public FragmentManager getFragmentManager() {
        return getSupportFragmentManager();

    public Fragment attachView(Object key, ChatHead chatHead) {
        // return the fragment which should be shown when the arrangment switches to maximized (on clicking a chat head)
        // you can use the key parameter to get back the object you passed in the addChatHead method.
        // this key should be used to decide which fragment to show.
        return new Fragment();

    public Drawable getChatHeadDrawable(Object key) {
        // this is where you return a drawable for the chat head itself based on the key. Typically you return a circular shape
        // you may want to checkout circular image library https://github.com/flipkart-incubator/circular-image
        return getResources().getDrawable(R.drawable.circular_view);

Then add the chat heads

chatContainer.addChatHead("head0", false); // you can even pass a custom object instead of "head0"
chatContainer.addChatHead("head1", true); // a sticky chat head (passed as 'true') cannot be closed and will remain when all other chat heads are closed.

And finally set the arrangement

chatContainer.setArrangement(MinimizedArrangement.class, null);

The view adapter is invoked when someone selects a chat head. In this example a String object ("head0") is attached to each chat head. You can instead attach any custom object, for e.g a Conversation object to denote each chat head. This object will represent a chat head uniquely and will be passed back in all callbacks.

Toggle arrangements

You can toggle between the Minimized and Maximized arrangement like this

chatContainer.setArrangement(MinimizedArrangement.class, null);
/** OR **/
chatContainer.setArrangement(MaximizedArrangement.class, null);


chatContainer.setListener(new ChatHeadListener() {
    public void onChatHeadAdded(Object key) {
        //called whenever a new chat head with the specified 'key' has been added

    public void onChatHeadRemoved(Object key, boolean userTriggered) {
        //called whenever a new chat head with the specified 'key' has been removed.
        // userTriggered: 'true' says whether the user removed the chat head, 'false' says that the code triggered it

    public void onChatHeadArrangementChanged(ChatHeadArrangement oldArrangement, ChatHeadArrangement newArrangement) {
        //called whenever the chat head arrangement changed. For e.g minimized to maximized or vice versa.

    public void onChatHeadAnimateStart(ChatHead chatHead) {
        //called when the chat head has started moving (

    public void onChatHeadAnimateEnd(ChatHead chatHead) {
        //called when the chat head has settled after moving

In normal scenarios you dont need to know when a chat head is selected because the fragment returned by the view adapter is automatically attached to it. For special cases where you need to perform any external action, you can use item selected listener.

chatContainer.setOnItemSelectedListener(new ChatHeadContainer.OnItemSelectedListener() {
    public boolean onChatHeadSelected(Object key, ChatHead chatHead) {
        if (chatContainer.getArrangementType() == MaximizedArrangement.class) {
            Log.d("springyheads","Clicked on " + key + " " +
                    "when arrangement was Maximized");
        return false; //returning true will mean that you have handled the behaviour and the default behaviour will be skipped


You can override the standard sizes by writing a custom class which extends the default config class. For e.g., the below class defines some standard properties and also the initial position of the chat head.

public class CustomChatHeadConfig extends ChatHeadDefaultConfig {
    public CustomChatHeadConfig(Context context, int xPosition, int yPosition) {
        setHeadHorizontalSpacing(ChatHeadUtils.dpToPx(context, -2));
        setHeadVerticalSpacing(ChatHeadUtils.dpToPx(context, 2));
        setHeadWidth(ChatHeadUtils.dpToPx(context, 50));
        setHeadHeight(ChatHeadUtils.dpToPx(context, 50));
        setInitialPosition(new Point(xPosition, yPosition));
        setCloseButtonHeight(ChatHeadUtils.dpToPx(context, 50));
        setCloseButtonWidth(ChatHeadUtils.dpToPx(context, 50));
        setCloseButtonBottomMargin(ChatHeadUtils.dpToPx(context, 100));
        setCircularRingWidth(ChatHeadUtils.dpToPx(context, 53));
        setCircularRingHeight(ChatHeadUtils.dpToPx(context, 53));

    public int getMaxChatHeads(int maxWidth, int maxHeight) {
        return (int) Math.floor(maxWidth / (getHeadWidth() + getHeadHorizontalSpacing(maxWidth, maxHeight))) - 1;

Once this config class is defined, you can set it to the manager

chatContainer.setConfig(new CustomChatHeadConfig(this, 0, 100);

Setting badge count

Do check out our library circular-image (https://github.com/flipkart-incubator/circular-image) for generating a circular drawable containing upto 4 smaller bitmaps as well as a badge count.


Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at


Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
See the License for the specific language governing permissions and
limitations under the License.

More info

You can find a working example in MainActivity of demo module included in the source. If you want to add a feature or fix a bug, please issue a pull request. This implementation of chat heads is meant to be used within the activity context and cannot be used inside a service.