パルカワ2

最近はFlutterをやっています

BottomNavigationViewのタイトルを常に表示したい

前提

どうやる

追記XMLで指定出来る方法を見つけた。

これで、ラベルが常に表示される。やったね!

    <android.support.design.widget.BottomNavigationView
        ...
        app:labelVisibilityMode="labeled"
        ...>

以下の内容は、動作しますが適切とは言えません。






@SuppressLint("RestrictedApi")
private fun disableBottomNavigationShiftMode() {
    val menuView = navigation.getChildAt(0) as BottomNavigationMenuView
    for (i in 0 until menuView.childCount) {
        val item = menuView.getChildAt(i) as BottomNavigationItemView
        item.setShifting(false)
    }
    menuView.labelVisibilityMode = 1
}

@SuppressLint("RestrictedApi")する必要がありヤダな〜というのが本音だけどまあしょうがない

考えたこと

BottomNavigationItemViewにsetShifting というメソッドがあるので、それをfalseに指定する。
これだけだとタブを切り替えたときにタイトルが消えてしまうため、BottomNavigationMenuViewのprivate APIである isShifting が falseを返すようにする必要がある。
(タブを切り替えるたび、BottomNavigationMenuViewのupdateMenuViewメソッドでViewの更新が行われている)

isShiftingは以下のようなロジックであるので、menuView.labelVisibilityMode = 1と指定するとfalseを返すようになる

    private boolean isShifting(int labelVisibilityMode, int childCount) {
        return labelVisibilityMode == -1 ? childCount > 3 : labelVisibilityMode == 0;
    }

ちなみに 1 ではなく 100 とかを指定しても多分動くんだけど、 BottomNavigationItemViewのsetCheckedlabelVisibilityModeが使われているので変な値を入れるのは避けたほうがよいと思う。
setViewValues の最後の引数が 0, 4, 8 となっているが、これは View.VISIBLEと対応していて、0はVISIBLE, 4はINVISIBLE, 8はGONEとなる。
定数を使わない理由はよくわからない。

    public void setChecked(boolean checked) {
        // 略
        switch(this.labelVisibilityMode) {
        case -1:
            if (this.isShifting) {
                if (checked) {
                    this.setViewLayoutParams(this.icon, this.defaultMargin, 49);
                    this.setViewValues(this.largeLabel, 1.0F, 1.0F, 0);
                } else {
                    this.setViewLayoutParams(this.icon, this.defaultMargin, 17);
                    this.setViewValues(this.largeLabel, 0.5F, 0.5F, 4);
                }

                this.smallLabel.setVisibility(4);
            } else if (checked) {
                this.setViewLayoutParams(this.icon, (int)((float)this.defaultMargin + this.shiftAmount), 49);
                this.setViewValues(this.largeLabel, 1.0F, 1.0F, 0);
                this.setViewValues(this.smallLabel, this.scaleUpFactor, this.scaleUpFactor, 4);
            } else {
                this.setViewLayoutParams(this.icon, this.defaultMargin, 49);
                this.setViewValues(this.largeLabel, this.scaleDownFactor, this.scaleDownFactor, 4);
                this.setViewValues(this.smallLabel, 1.0F, 1.0F, 0);
            }
            break;
        case 0:
            if (checked) {
                this.setViewLayoutParams(this.icon, this.defaultMargin, 49);
                this.setViewValues(this.largeLabel, 1.0F, 1.0F, 0);
            } else {
                this.setViewLayoutParams(this.icon, this.defaultMargin, 17);
                this.setViewValues(this.largeLabel, 0.5F, 0.5F, 4);
            }

            this.smallLabel.setVisibility(4);
            break;
        case 1:
            if (checked) {
                this.setViewLayoutParams(this.icon, (int)((float)this.defaultMargin + this.shiftAmount), 49);
                this.setViewValues(this.largeLabel, 1.0F, 1.0F, 0);
                this.setViewValues(this.smallLabel, this.scaleUpFactor, this.scaleUpFactor, 4);
            } else {
                this.setViewLayoutParams(this.icon, this.defaultMargin, 49);
                this.setViewValues(this.largeLabel, this.scaleDownFactor, this.scaleDownFactor, 4);
                this.setViewValues(this.smallLabel, 1.0F, 1.0F, 0);
            }
            break;
        case 2:
            this.setViewLayoutParams(this.icon, this.defaultMargin, 17);
            this.largeLabel.setVisibility(8);
            this.smallLabel.setVisibility(8);
        }
        // 略
    }