ls -al

仮想通貨やプログラミングに関する事などをつらつらと書き綴ります

Androidで「もっと読む」ボタン付TextViewを作ってみる

Androidで「もっと読む」ボタン付のTextViewを作ってみました。具体的には、「長文のテキストを省略して途中まで表示し、かつ、後ろ部分に透明なグラデーションをかけて続きがあることを期待させ、下にあるボタンを押すことで続きが表示されるTextView」です。


結局どんなものなのか

動画で見るとこんな感じです。
最初は以下のような見た目です。テキストが表示され、下の方の行は徐々に透過されています。

before

「READ_MORE」ボタンを押すと以下のようにテキストが展開され続きが読めるようになります。

after

では作っていきましょう。


作り方

Layout

まずはこんな感じのレイアウトを作ります。

layout

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity"
        tools:layout_editor_absoluteY="81dp">

    <TextView
            android:layout_width="wrap_content"
            android:layout_height="0dp"
            android:text="Hello World!"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:id="@+id/textView"
            />

    <Button
            android:text="read_more"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/button"
            app:layout_constraintTop_toBottomOf="@+id/textView"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"/>

</android.support.constraint.ConstraintLayout>

なんてことはない普通のViewです。テキストを中央上に配置し、その下にボタンを配置しただけです。

Activity

Activityも作っていきます。

import android.graphics.Color
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import android.graphics.Shader
import android.graphics.LinearGradient


class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val textView = findViewById<TextView>(R.id.textView)
        val button = findViewById<Button>(R.id.button)
        textView.maxLines = 6
        textView.text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, " +
                "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. " +
                "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris " +
                "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in " +
                "reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla " +
                "pariatur. Excepteur sint occaecat cupidatat non proident, sunt in " +
                "culpa qui officia deserunt mollit anim id est laborum." +
                "Lorem ipsum dolor sit amet, consectetur adipiscing elit, " +
                "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. " +
                "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris " +
                "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in " +
                "reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla " +
                "pariatur. Excepteur sint occaecat cupidatat non proident, sunt in " +
                "culpa qui officia deserunt mollit anim id est laborum."
        val runnable = Runnable {
            val shader = LinearGradient(
                    0F, (textView.height * 0.5).toFloat(), 0F, textView.height.toFloat()*0.95F, textView.currentTextColor, Color.TRANSPARENT, Shader.TileMode.CLAMP)
            textView.paint.shader = shader
        }
        textView.post(runnable)
        button.setOnClickListener {
            textView.maxLines = Integer.MAX_VALUE
            val shader = LinearGradient(
                    0F, 0F, 0F, textView.height.toFloat(), textView.currentTextColor, textView.currentTextColor, Shader.TileMode.CLAMP)
            textView.paint.shader = shader
        }
    }
}

ポイントはLinearGradientを使用しているところです。これはViewに対して直線方向のグラデーションを適用できるクラスです。

val shader = LinearGradient(
        0F, (textView.height * 0.5).toFloat(), 0F, textView.height.toFloat()*0.95F, textView.currentTextColor, Color.TRANSPARENT, Shader.TileMode.CLAMP)

この部分では、上記LinearGradientを使用して、縦(X方向)にtextViewの50%の高さで現在のテキストカラーから開始し、95%の高さで透明になるグラデーションを作成しています。その後これを実際に適用する処理が描画後に走るようにpostしています。

ボタンが押された場合は、

textView.maxLines = Integer.MAX_VALUE

こちらでmaxLinesの制限を取り払い

val shader = LinearGradient(
        0F, 0F, 0F, textView.height.toFloat(), textView.currentTextColor, textView.currentTextColor, Shader.TileMode.CLAMP)
textView.paint.shader = shader

こちらでさきほどのグラデーションを無効にしています。これでボタンを押すことで続きが表示される機能が実現できます!


参考