Android – Building a Fidget spinner (Part 1)

2 min read

Recently i have seen many people building fidget spinners apps  so i decided to take some time and build my own fidget spinner app and post it online.

Note: This application is built completely in Kotlin and was done using Android studio 3.0 (Alpha). this is not a Kotlin tutorial, for those of you who do not know how to setup Kotlin for android development, please see HERE.

The goal of this tutorial is very straight forward, create an application with an ImageView that rotates and vibrates the phone on press.

Lets start with the XML

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    android:id="@+id/container"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.josiassena.fidgetspinner.MainActivity">

    <android.support.v7.widget.AppCompatImageView
        android:id="@+id/ivFidget"
        android:layout_width="300dp"
        android:layout_height="300dp"
        app:srcCompat="@drawable/fidget_spinner_yellow"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintRight_toRightOf="parent"/>

</android.support.constraint.ConstraintLayout>

The xml is pretty straight forward, theres a ConstraintLayout with a single image view inside of it.

Now lets take a look at the only activity in the application, the MainActivity.

First we want to add an onTouchListener to the ivFidget. This is what will notify us when the spinner has been touched. In order to do this we do the following on the onCreate of the activity.

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        ivFidget.setOnTouchListener { v, event ->

        }
    }
}

There are two events we want to listen to. When the user presses the image and when they let go. In order to do this we do:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        ivFidget.setOnTouchListener { v, event ->
            when (event.action) {
                KeyEvent.ACTION_DOWN -> {

                }
                KeyEvent.ACTION_UP -> {

                }
            }

            true
        }
    }
}

First things first, lets vibrate the device when the spinner is touched, and lets stop vibrating when the spinner is released.

class MainActivity : AppCompatActivity() {

    lateinit var vibrator: Vibrator // get ready to init the vibrator

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Initialize the vibrator
        vibrator = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator

        ivFidget.setOnTouchListener { v, event ->
            when (event.action) {
                KeyEvent.ACTION_DOWN -> {
                    startVibration()
                }
                KeyEvent.ACTION_UP -> {
                    stopVibration()
                }
            }

            true
        }
    }

    private fun startVibration() {
        // if the device can vibrate, then lets vibrate!
        if (vibrator.hasVibrator()) {
            vibrator.vibrate(500000)
        }
    }

    private fun stopVibration() {
        // If the device can vibrate then lets stop all of its vibrations
        if (vibrator.hasVibrator()) {
            vibrator.cancel()
        }
    }
}

The last and final piece of this entire application is to spin the spinner using a RotateAnimation.

class MainActivity : AppCompatActivity() {

    lateinit var vibrator: Vibrator

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        vibrator = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator

        ivFidget.setOnTouchListener { v, event ->
            when (event.action) {
                KeyEvent.ACTION_DOWN -> {
                    ivFidget.startAnimation(getSpinAnimation())
                    startVibration()
                }
                KeyEvent.ACTION_UP -> {
                    ivFidget.clearAnimation()
                    stopVibration()
                }
            }

            true
        }
    }

    private fun getSpinAnimation(): RotateAnimation {
        val spin = RotateAnimation(0f, 1000000f, Animation.RELATIVE_TO_SELF, 0.5f,
                Animation.RELATIVE_TO_SELF, 0.5f)

        spin.duration = Math.abs(Animation.INFINITE.toLong()) // must be positive
        spin.repeatCount = Animation.INFINITE
        spin.interpolator = LinearOutSlowInInterpolator()
        spin.fillAfter = false

        return spin
    }

    private fun startVibration() {
        if (vibrator.hasVibrator()) {
            vibrator.vibrate(500000)
        }
    }

    private fun stopVibration() {
        if (vibrator.hasVibrator()) {
            vibrator.cancel()
        }
    }
}

Thats it. Run the app and when the image view is clicked the image will spin and vibrate the device. For the full source code of this please visit HERE.

This is all for this post, hope you guys enjoy it. In the next post we will take a look on how to spin and move the spinner at the same time.

Until next time.