AndroidのTextViewで省略表示（マーキー、...）

TextViewの省略表示（マーキーや...）について調べました。

# layout xmlで設定する場合
[android:ellipsize](https://developer.android.com/reference/android/widget/TextView#attr_android:ellipsize)属性を設定することで、ビューの幅よりも長い文字の場合に省略表示されます。

```xml:layout.xml
    <TextView
        android:id="@+id/text2"
        android:focusable="true"
        android:ellipsize="none"
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:gravity="center_vertical"
        android:singleLine="true"
        android:text="1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" />
```

| Constant | Description | Example |
|:---------|:-----------:|:------------------:|
| none     | 省略なし      | １２３４５６７ |
| start    | 先頭を省略    | …４５６７８９ |
| middle   | 中央を省略    | １２３…789 |
| end      | 最後を省略    | 123456… |
| marquee  | スクロール     |         |

**marqueeについては、TextViewにフォーカスがあたった際にスクロールが実行されます。**
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254520/d40293fd-a786-a557-207a-9bd794014fba.png" width=30%>


# setEllipsize methodで設定する場合
[setEllipsize](https://developer.android.com/reference/android/widget/TextView#setEllipsize(android.text.TextUtils.TruncateAt))でも設定することができます。

public void setEllipsize (TextUtils.TruncateAt where)

| Parameters | Description | Example   |
|:-----------|:-----------:|:---------:|
| null       | 省略なし      | １２３４５６７   |
| START      | 先頭を省略    | ...４５６７８９ |
| MIDDLE     | 中央を省略    | １２３...789 |
| END        | 最後を省略    | 123456... |
| MARQUEE    | スクロール     |           |
| END_SMALL  | 最後を省略    | 1234567..  |
※END_SMALLはSdkVersion 28からとなります。

# marqueeの注意点
marqueeについては、TextViewにフォーカスがあたった際にスクロールが実行されます。
TextViewにフォーカスをあてられない場合（例：RecyclerViewでアイテムに複数のTextViewがある場合）は[setSelected](https://developer.android.com/reference/android/widget/TextView#setSelected(boolean))をtrueにする必要があります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254520/2e4cfed4-b39b-7bef-6139-3dd911ffe8a5.png" width=30%>

### サンプルコード
例：RecyclerViewでアイテムに複数のTextViewがある場合

```kotlin:TextViewSampleActivity.kt
class TextViewSampleActivity : AppCompatActivity() {

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

        val recyclerView = findViewById<RecyclerView>(R.id.list)
        recyclerView.adapter = TextViewSampleAdapter(this)
        val layoutManager = LinearLayoutManager(this)
        recyclerView.layoutManager = layoutManager
        recyclerView.addItemDecoration(DividerItemDecoration(this, layoutManager.orientation))
    }
}
```

```xml:activity_text_view_sample.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:focusable="true"
    android:orientation="vertical">

    <TextView
        android:id="@+id/ellipsize"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/targetText"
        android:ellipsize="none"
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:singleLine="true"
        android:text="1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" />
</LinearLayout>
```

**ポイントは、RecyclerViewのアイテムにフォーカスがあたった際に、isSelectedをtrueにすることです。**

```kotlin:TextViewSampleAdapter.kt
class TextViewSampleAdapter(
        context: Context) : RecyclerView.Adapter<TextViewSampleAdapter.ListAdapterHolder>() {
    private val inflater = LayoutInflater.from(context)

    private val ID_NONE = 0
    private val ID_START = 1
    private val ID_MIDDLE = 2
    private val ID_END = 3
    private val ID_MARQUEE = 4
    private val ID_END_SMALL = 5
    private val ID_ARRAY = arrayOf(ID_NONE, ID_START, ID_MIDDLE, ID_END, ID_MARQUEE, ID_END_SMALL)

    class ListAdapterHolder(view: View) : RecyclerView.ViewHolder(view)

    override fun getItemCount(): Int {
        return ID_ARRAY.size
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListAdapterHolder {
        val view = inflater.inflate(R.layout.list_adapter_item, parent, false)
        return ListAdapterHolder(view)
    }

    override fun onBindViewHolder(holder: ListAdapterHolder, position: Int) {
        holder.itemView.setOnFocusChangeListener { v, hasFocus ->
            if (hasFocus) {
                if (position == ID_MARQUEE) holder.itemView.targetText.isSelected = true
            } else {
                if (position == ID_MARQUEE) holder.itemView.targetText.isSelected = false
            }
        }
        when (position) {
            ID_NONE -> setEllipsize(holder, "ellipsize NONE", null)
            ID_START -> setEllipsize(holder, "ellipsize START", TextUtils.TruncateAt.START)
            ID_MIDDLE -> setEllipsize(holder, "ellipsize MIDDLE", TextUtils.TruncateAt.MIDDLE)
            ID_END -> setEllipsize(holder, "ellipsize END", TextUtils.TruncateAt.END)
            ID_MARQUEE -> setEllipsize(holder, "ellipsize MARQUEE", TextUtils.TruncateAt.MARQUEE)
            else -> setEllipsize(holder, "ellipsize END_SMALL", TextUtils.TruncateAt.END_SMALL)
        }
    }

    private fun setEllipsize(holder: ListAdapterHolder, text: String, where: TextUtils.TruncateAt?) {
        holder.itemView.ellipsize.setText(text)
        holder.itemView.targetText.ellipsize = where
    }
}
```

```xml:list_adapter_item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:focusable="true"
    android:orientation="vertical">

    <TextView
        android:id="@+id/ellipsize"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/targetText"
        android:ellipsize="none"
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:singleLine="true"
        android:text="1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" />
</LinearLayout>
```