LoginSignup
2
1

More than 3 years have passed since last update.

ImageViewの表示領域内に収まらない大きな画像を自動スクロールで表示する

Last updated at Posted at 2019-11-27

 きっかけ

  • 2019 Material Design Awardで入賞したTrip.comを見て、自動スクロールで画像を表示していて良い感じだなと思ったので試してみました。

record-191125110141.gif


動作環境

  • Android Studio 3.5.2
  • Android 10, 5

 サンプルコードについて

  • 画像の自動スクロール
  • カスタムビューで実装する

 画像の自動スクロール


 画像の自動スクロール

activity_scroll_image_view.xml
    <ImageView
        android:id="@+id/sushi"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:contentDescription="@null"
        android:scaleType="matrix"
        android:src="@drawable/sushi"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

 画像の自動スクロール

ScrollImagaeViewActivity.kt
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_scroll_imagae_view)

        val image = findViewById<ImageView>(R.id.sushi)
        image.doOnLayout {
            var repeatCount = 0
            // imageViewに格納したDrawableの幅を取得する
            val drawableWidth = image.drawable.intrinsicWidth
            val imageWidth = image.width
            var isScrollLeftToRight = true
            var currentX = 0

            val handler = Handler()
            val r = object : Runnable {
                override fun run() {

                    // 右端まで表示したらスクロール方向を左へ変更する
                    if (drawableWidth < currentX + imageWidth) {
                        isScrollLeftToRight = false
                    }

                    if (currentX < 0) {
                        repeatCount++
                        isScrollLeftToRight = true
                    }

                    if (repeatCount == 2) return

                    val scrollX = getScrollX(isScrollLeftToRight)
                    currentX += scrollX

                    image.scrollBy(
                        scrollX,
                        0
                    )

                    handler.postDelayed(this, 10)
                }
            }
            handler.post(r)
        }
    }

動かしてみました

record-191125112627.gif


美味しそうな寿司が動きました :relaxed:


カスタムビューで実装する


カスタムビューで実装する

activity_scroll_image_view.xml
    <jp.co.yiwaisako.ui_sample.AutoHorizontalScrollImageView
        android:id="@+id/sushi"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:contentDescription="@null"
        android:src="@drawable/sushi"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

カスタムビューで実装する

AutoHorizontalScrollImageView(1)
    init {
        scaleType = ScaleType.MATRIX
    }

    // スクロールを繰り返す上限回数
    var maxRepeatCount = 1

    // 1回のスクロール量
    var scrollValueXForOneTime = 1

    // スクロールした回数
    private var repeatCount = 0

    // 現在のX位置
    private var currentX = 0

    // 繰り返すかどうか
    private val isAutoScroll: Boolean
        get() {
            return repeatCount < maxRepeatCount
        }

    // スクロール方向
    private var direction: Direction = Direction.TO_RIGHT

    // スクロール量
    private val scrollValueX: Int
        get() {
            return when (direction) {
                Direction.TO_RIGHT -> {
                    scrollValueXForOneTime
                }
                Direction.TO_LEFT -> {
                    -scrollValueXForOneTime
                }
            }
        }

    enum class Direction {
        TO_RIGHT,
        TO_LEFT
    }

カスタムビューで実装する

AutoHorizontalScrollImageView(2)
    override fun onDraw(canvas: Canvas?) {
        if (isAutoScroll) {
            scrollTo(scrollValueX)
            // scrollTo()の後に実行してください
            decideDirectionAfterScrolled()
        }
        super.onDraw(canvas)
    }

    private fun scrollTo(scrollValueX: Int) {
        currentX += scrollValueX
        scrollBy(scrollValueX, 0)
    }

    private fun decideDirectionAfterScrolled() {
        if (currentX <= 0) {
            repeatCount++
            direction = Direction.TO_RIGHT
        }
        if (drawable.intrinsicWidth <= currentX + width) {
            direction = Direction.TO_LEFT
        }
    }

サンプルレイアウトに配置

  • record-191126194714.gif

まとめ

  • 水平方向の自動スクロールを実装しました
  • リピート回数、スクロール量などの調整をDatabindingで対応しても良さそう(今回は未対応です)
  • コードのscrollTo()の後に実行してくださいのコメントを無くしたい(メソッドの実行順番を利用者に意識させない)のですがよい修正案が思いつかなく、アドバイスありましたらお願いします。 :clap:

リンク

2
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1