読者です 読者をやめる 読者になる 読者になる

無趣味な人

生まれてこの方、無趣味。ハマったものこれといって特になし。

Androidアプリ開発:リソースIDを文字列から

テーマの変更を動的にやりたかった。 テーマはPreferenceでListPreferenceを使用して、ユーザーに選択してもらう。 選択したテーマを元に動的に変更する。

配列は以下の感じ。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="theme_array">
        <item>白</item>
        <item>黒</item>
        <item>赤</item>
    </string-array>
    <array name="theme_array_values">
        <item>Theme.Light</item>
        <item>Theme.Dark</item>
        <item>Theme.Red</item>
    </array>
</resources>

Preferenceは以下の感じ。

<ListPreference
    android:defaultValue="Theme.Light"
    android:dialogTitle="テーマ選択"
    android:entries="@array/theme_array"
    android:entryValues="@array/theme_array_values"
    android:key="theme_setting"
    android:summary="ツールバーや背景の色を変更する"
    android:title="テーマの変更"/>

テーマ変更はsetThemeを使えばいいのだが、リソースIDをどう取得すればいいのかわからなかった。 条件分枝しなければならないのかと思ったら簡単な方法があった。 getIdentifierを使えば、文字列からリソースIDを取得できる。

String theme_setting = sharedPreferences.getString("theme_setting", "Theme.Light");”;
Resources res = getResources();
int viewId = res.getIdentifier(theme_setting, "style", getPackageName());
setTheme(viewId);

上記をActivityごとにやる。

NavigationViewのMenu Itemを動的に非表示に

DrawerLayoutとNavigationViewでメニューを作成した。 状態によって一部のMenu Itemを表示したり非表示にしたりしたかった。 動的にメニューを追加しようとした。 が、すべてのメニューをmenu.xmlで定義しておいて動的に非表示にするのが楽だった。

//NavigationView
mNavigationView = (NavigationView) findViewById(R.id.main_navigation_view);
mNavigationView.setNavigationItemSelectedListener(this);

//省略

//非表示にしたい時に以下をする
Menu menu = mNavigationView.getMenu();
MenuItem menuItem1 = menu.findItem(R.id.menu_item_1);
menuItem1.setVisible(false);

別のプロジェクトのモジュール利用をやめて、モジュールをインポートした

Android Studioでライブラリプロジェクトを作成して、そこからモジュールを参照する形にしていた。が、メンテナンス上、自分のプロジェクトにモジュールを追加して使うようにしたくなった。 その時のメモ

1. setting.gradleから削除

setting.gradleに以下の記述をして、外部ライブラリプロジェクトからモジュールを追加していたが削除した。

include ':testlib'
project(':testlib').projectDir = new File(settingsDir, '../MyLib/testlib')

2. app の build.gradleから削除

appのbuild.gradleのdependenciesからライブラリモジュールを削除

compile project(':testlib')

syncさせると確認があるので「OK」を押す。 モジュールがプロジェクトから消える。 当然、ビルドするとエラーがいっぱい出る。

追記:ここはやらなくてもいいかも

3.モジュールをインポートする

[File] > [New] > [Import Module]でモジュールを選択する。 ファイル一式がコピーされ、setting.gradleは自動で以下のように変更される。

include ':app', ':testlib'

その後、app の build.gradleのdependenciesに

compile project(':testlib')

を追加する。

PagerSlidingTabStripのNullPointerException

ViewPagerIndicatorからPagerSlidingTabStripに変更して使っていたら、以下のようなエラーが吐かれてしまう。

java.lang.NullPointerException
        at com.astuetz.PagerSlidingTabStrip$PageListener.onPageScrolled(
                PagerSlidingTabStrip.java:361)
        at android.support.v4.view.ViewPager.onPageScrolled(ViewPager.java:1712)
        at android.support.v4.view.ViewPager.pageScrolled(ViewPager.java:1633)
        at android.support.v4.view.ViewPager.scrollToItem(ViewPager.java:581)
        at android.support.v4.view.ViewPager.onLayout(ViewPager.java:1600)
        ...

ViewPagerIndicatorを使用していた時にはでないエラーだった。 PagerSlidingTabStripのバグのようなのだが、回避方法はあった。

エラーは、PagerSlidingTabStripにセットするViewPagerの保持している配列の長さが0の時に起こるようだ。そこで、ViewPagerのArrayListの長さを確認してから、PagerSlidingTabStripにセットするようにした。

mViewPager.setAdapter(mViewPagerAdapter);

PagerSlidingTabStrip tabs = (PagerSlidingTabStrip) findViewById(R.id.tabs);
if(mViewPagerAdapter.getCount() > 0){
     tabs.setViewPager(mViewPager);
}

抜粋だがこんな感じ。getCountは自分で作ったもので、ViewPagerAdapterの中のArrayListの長さを返す。

Toolbarの文字の色を変更する

f:id:itereta:20141215174816j:plain

公開中のAndroidアプリをマテリアルデザイン風に変更するために、Toolbarを使うことにした。

テーマは「Theme.AppCompat.Light.NoActionBar」で。 すると、マテリアルデザイン風にしたいのに、Toolbarの中の文字が黒くてダサい。

f:id:itereta:20170406222036p:plain

この文字の色を変更するだけで苦労してしまった。

最初は、単純に

<style name="MyCustomTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="colorPrimary">#0091EA</item>
    <item name="colorAccent">#607D8B</item>
    <item name="android:textColorPrimary">@android:color/white</item>
    <item name="android:textColorSecondary">@android:color/white</item>
</style>

というテーマを作り、AndroidManifest.xmlに登録した。 しかし、こうすると他のandroid:textColorPrimaryを使っている箇所の文字の色も変わってしまった。Toolbarだけのためだけにアプリ全体のtextColorPrimaryを変更するのは色々不都合なのでやめにした。

色々試した方法は二つ。

方法1. 別のスタイルを登録する
方法2. ただのビューとしてスタイルを定義する

「setSupportActionBar」を使ってアクションバーとしてセットする場合は方法1でしかできない。 元々あるアプリはこの方が変更点が少なくて楽であった。 しかし、柔軟なスタイル変更はできない。 方法2の方は変更点が多いが柔軟に色々変更できるので私はこちらを選択した。

方法1

自分のカスタムテーマの下にToolbar専用のテーマを作り、レイアウトファイルでToolbarに設定した。

<style name="MyCustomTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="colorPrimary">#0091EA</item>
    <item name="colorAccent">#607D8B</item>
</style>


<style name="MyCustomTheme.Toolbar" parent="MyCustomTheme">
    <item name="android:textColorPrimary">@android:color/white</item>
    <item name="android:textColorSecondary">@android:color/white</item>
</style>

上のように作っておいて、AndroidManifest.xmlにはMyCustomThemeを登録。 ToolbarのlayoutにMyCustomTheme.Toolbarを登録する。

<android.support.v7.widget.Toolbar
                android:id="@+id/my_toolbar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:theme="@style/MyCustomTheme.Toolbar"
                app:popupTheme="@style/Theme.AppCompat.Light">

このようにすれば、Toolbarの文字だけが白くなる。

方法2

「setSupportActionBar」を使わずActionbarとしなければ、styleを設定できる。 要するに、ToolbarをただのViewとして扱うということ。

<style name="MyCustomTheme.Light" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="colorPrimary">#0091EA</item>
    <item name="colorAccent">#607D8B</item>

    <!-- Toolbarのnavigation & overflow icon の色 -->
    <item name="colorControlNormal">@color/white</item>

    <!-- Toolarのスタイル -->
    <item name="toolbarStyle">@style/MyCustomTheme.Toolbar</item>
</style>

<style name="MyCustomTheme.Toolbar" parent="Widget.AppCompat.Toolbar">
    <item name="titleTextAppearance">
        @style/TextAppearance.AppCompat.Widget.ActionBar.Title.Inverse
    </item>
    <item name="subtitleTextAppearance">
        @style/TextAppearance.AppCompat.Widget.ActionBar.Subtitle.Inverse
    </item>
</style>

私は結局、方法2を使うことにした。方法1ではソースコードの変更は少ないのだが、自由度が少なく自分のやりたいことができないことがあるためだ。

以上

Navigation Drawer使用時のaddDrawerListenerでのエラー

f:id:itereta:20141215174816j:plain

Toolbarにメニューアイコンを表示して、そのアイコンをタップすればNavigation Drawerを開くようにしたかった。 ActionBarDrawerToggleを使えば実現できるのだが、大体のサンプルでは以下のように書いてあった。

DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawerLayout); 
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle( this, drawer, toolbar,R.string.drawer_open, R.string.drawer_close); 
drawer.addDrawerListener(toggle);
toggle.syncState();

しかし、以下のようなエラーが表示された。

Error:(**,**)エラー: シンボルを見つけられません
シンボル: メソッド addDrawerListener(ActionBarDrawerToggle)
場所: タイプDrawerLayoutの変数 mDrawerLayout

理由がわからないのだが、addDrawerListenerが悪いらしい。 これをsetDrawerListenerに変更したら、エラーもなくなり動作確認もできた。

本来はsetDrawerListenerはdeprecatedだが私の環境では動作の問題はない。