Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
44
Help us understand the problem. What is going on with this article?
@yasuX

[Android] フリック入力機能を実装してみた

More than 1 year has passed since last update.

完成形!

flickMovie.gif

はじめに

フリック機能を搭載したアプリを作りたかったのですが、公式を見ると
フリックされたことを検知する処理しか掲載されていなかったので、
こちらの記事を参考にさせていただき、自作でリスナーを作成しました。

これからフリック入力機能を実装したいと思う方の一助になればと思います。

実装

FlickListener

FlickListener.kt
class FlickListener(
    private val listener: Listener
) : View.OnTouchListener {

    // フリックイベントのリスナー
    interface Listener {
        fun onButtonPressed()
        fun onButtonReleased()
        fun onFlickToLeft()
        fun onFlickToRight()
        fun onFlickToUp()
        fun onFlickToDown()
        fun onFlickOutside()
        fun onSwipingOnLeft()
        fun onSwipingOnRight()
        fun onSwipingOnUp()
        fun onSwipingOnDown()
        fun onSwipingOnCenter()
        fun onSwipingOutside()
    }

    companion object {
        // フリック判定時の遊び。小さいほど判定が敏感になる
        const val DEFAULT_PLAY = 100f
    }

    private val play = DEFAULT_PLAY
    private var startX: Float = 0f
    private var startY: Float = 0f
    private var endX: Float = 0f
    private var endY: Float = 0f

    override fun onTouch(v: View, event: MotionEvent): Boolean {
        when (event.action) {
            MotionEvent.ACTION_DOWN -> touchDown(event)
            MotionEvent.ACTION_MOVE -> swipe(event)
            MotionEvent.ACTION_UP -> touchOff(event)
        }
        return true
    }

    private fun touchDown(event: MotionEvent) {
        startX = event.x
        startY = event.y
        listener.onButtonPressed()
    }

    private fun swipe(event: MotionEvent) {
        endX = event.x
        endY = event.y
        when {
            outScope()   -> listener.onSwipingOutside()
            leftScope()  -> listener.onSwipingOnLeft()
            rightScope() -> listener.onSwipingOnRight()
            upScope()    -> listener.onSwipingOnUp()
            downScope()  -> listener.onSwipingOnDown()
            else         -> listener.onSwipingOnCenter()
        }
    }

    private fun touchOff(event: MotionEvent) {
        endX = event.x
        endY = event.y
        when {
            outScope()   -> listener.onFlickOutside()
            leftScope()  -> listener.onFlickToLeft()
            rightScope() -> listener.onFlickToRight()
            upScope()    -> listener.onFlickToUp()
            downScope()  -> listener.onFlickToDown()
            else         -> listener.onButtonReleased()
        }
    }

    private fun leftScope(): Boolean = endX < startX - play
    private fun rightScope(): Boolean = startX + play < endX
    private fun upScope(): Boolean = endY < startY - play
    private fun downScope(): Boolean = startY + play < endY
    private fun outScope(): Boolean =
        (leftScope() && upScope()) || (rightScope() && upScope()) || 
                (leftScope() && downScope()) || (rightScope() && downScope())
}

startX, startY, endX, endYplay との関係ついては、次の図を見てもらえればわかると思います!
ボタンのサイズや感度に合うように、play を変更して調整しましょう。

FlickScope.png

MainActivity

centerボタンにFlickListernerを設定し、そのプロパティをオブジェクト式で実装します。

MainActivity.kt
class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        center.setOnTouchListener(FlickListener(flickListener))
    }

    private val flickListener = object : FlickListener.Listener {

        override fun onButtonPressed() {
            center.setBackgroundButtonColor(R.color.pressedButtonColor)
            toggleVisible()
        }

        override fun onSwipingOnCenter() = center.settingSwipe()
        override fun onSwipingOnLeft() = left.settingSwipe()
        override fun onSwipingOnRight() = right.settingSwipe()
        override fun onSwipingOnUp() = top.settingSwipe()
        override fun onSwipingOnDown() = bottom.settingSwipe()

        override fun onButtonReleased() = settingFlick("中")
        override fun onFlickToLeft() = settingFlick("左")
        override fun onFlickToRight() = settingFlick("右")
        override fun onFlickToUp() = settingFlick("上")
        override fun onFlickToDown() = settingFlick("下")

        private fun settingFlick(label: String) {
            showToast(label)
            Thread.sleep(100)
            toggleInvisible()
            clearAll()
        }

        private fun toggleVisible() {
            top.visibility = View.VISIBLE
            left.visibility = View.VISIBLE
            right.visibility = View.VISIBLE
            bottom.visibility = View.VISIBLE
        }

        private fun toggleInvisible() {
            top.visibility = View.INVISIBLE
            left.visibility = View.INVISIBLE
            right.visibility = View.INVISIBLE
            bottom.visibility = View.INVISIBLE
        }

        private fun clearAll() {
            center.setBackgroundButtonColor(R.color.baseButtonColor)
            left.setBackgroundButtonColor(R.color.baseButtonColor)
            right.setBackgroundButtonColor(R.color.baseButtonColor)
            top.setBackgroundButtonColor(R.color.baseButtonColor)
            bottom.setBackgroundButtonColor(R.color.baseButtonColor)
        }

        private fun View.settingSwipe() {
            clearAll()
            setBackgroundButtonColor(R.color.pressedButtonColor)
        }

        private fun View.setBackgroundButtonColor(@ColorRes resId: Int) =
            setBackgroundColor(ContextCompat.getColor(applicationContext, resId))

        private fun showToast(msg: String) = Toast.makeText(this@MainActivity, msg, Toast.LENGTH_LONG).show()
    }
}

おわりに

今回、フリックする速度は考慮していません!
それでも機能としては十分だったので、よければ使ってみてください\(^o^)/

また、この機能の実装自体は難しいものではなかったので、
Android初心者の方の勉強用としても最適だと思いました!

もっとこうすれば良くなる!などの改善点やアドバイスがあれば教えていただけると嬉しいです!

44
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
yasuX
Golang
sorich
SORICHはWebシステム開発を主軸に、デザイン・Web制作・アプリ開発・IoTまで、クライアントの幅広いニーズに対応する技術者集団です。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
44
Help us understand the problem. What is going on with this article?