web-dev-qa-db-ja.com

Android-実行時にカスタムタイトルビューを変更

アプリケーションで各アクティビティのカスタムタイトルビューを使用しています。アクティビティの1つで、ボタンのクリックに基づいて、カスタムタイトルビューを変更する必要があります。これで、setFeatureIntを呼び出すたびに正常に機能します。

しかし、カスタムタイトルのアイテムを更新しようとすると(ボタンのテキストやタイトルのテキストビューを変更するなど)、更新は行われません。

コードをデバッグすると、テキストビューとボタンのインスタンスがnullではなく、カスタムタイトルバーも表示されます。ただし、テキストビューまたはボタンのテキストは更新されません。他の誰かがこの問題に直面しましたか?どうすれば解決できますか?

ありがとう。

[〜#〜]編集[〜#〜]

これが私が試したものです。 postInvalidateを呼び出しても更新されません。

    getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.text_title);

    TextView databar = (TextView) findViewById(R.id.title_text);
    databar.setText("Some Text");
    databar.postInvalidate();

    Button leftButton = (Button) findViewById(R.id.left_btn);
    leftButton.setOnClickListener(mLeftListener);
    leftButton.setText("Left Btn");
    leftButton.postInvalidate();

    Button rightBtn = (Button) findViewById(R.id.right_btn);
    rightBtn.setOnClickListener(mRightListener);
    rightBtn.postInvalidate();
23
lostInTransit

問題は、唯一の Window 実装( PhoneWindow )が LayoutInflater を使用することですsetFeatureIntメソッド内で、 inflate およびattachToRoot=trueを使用して新しいレイアウトをインスタンス化します。その結果、setFeatureIntを呼び出すと、新しいレイアウトは置換ではなく内部タイトルコンテナーに添付され、したがって、互いの上に描画されます。

これを回避するには、setFeatureIntの代わりに次のヘルパーメソッドを使用します。ヘルパーは、新しいカスタムタイトル機能が設定される前に、内部のタイトルコンテナーからすべてのビューを削除するだけです。


private void setCustomTitleFeatureInt(int value) {
    try {
        // retrieve value for com.Android.internal.R.id.title_container(=0x1020149)
        int titleContainerId = (Integer) Class.forName(
            "com.Android.internal.R$id").getField("title_container").get(null);

        // remove all views from titleContainer
        ((ViewGroup) getWindow().findViewById(titleContainerId)).removeAllViews();

        // add new custom title view 
        getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, value);

    } catch(Exception ex) {
        // whatever you want to do here..
    }
}

現在のsetFeatureIntの動作が意図したものであるかどうかはわかりませんが、どちらかといえば文書化されていないため、Android devs ;)

[〜#〜]編集[〜#〜]

コメントで指摘されているように、前述の回避策は理想的ではありません。 com.Android.internal.R.id.title_container定数に依存する代わりに、新しいカスタムタイトルを設定するたびに、古いカスタムタイトルを単にhideすることができます。

2つのカスタムタイトルレイアウトがあるとします。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout Android:id="@+id/custom_title_1" ...

そして

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout Android:id="@+id/custom_title_2" ...

custom_title_1custom_title_2に置き換えたい場合は、前者を非表示にし、setFeatureIntを使用して後者を追加できます。

findViewById(R.id.custom_title_1).setVisibility(View.GONE);
getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.custom_title_2);
31
Josef Pfleger

これを行う正しい方法は次のとおりです。

requestWindowFeature( Window.FEATURE_CUSTOM_TITLE );
setContentView( R.layout.my_layout );
getWindow().setFeatureInt( Window.FEATURE_CUSTOM_TITLE, R.layout.my_custom_title );
super.onCreate( savedInstanceState );

これらのステートメントの順序は非常に重要であることに注意してください。

他のステートメントの前にsuper.onCreate()を呼び出すと、空白のタイトルバーが表示されます。タイトルバーIDを見つけてそこからすべてのビューを削除するハックは修正されますが、お勧めできません。

13
James Oltmans

ちょうど私の2cの価値:

MapActivityで作業しているときに、カスタムタイトルをリクエストすると、タイトルがまったく表示されませんでした。

幸い、私がやりたかったのは、タイトルテキストを別の方法で設定することだけでしたが、すぐに、onCreate()内でsetTitle()を呼び出すだけでうまくいくことに気付きました(setContentView()を呼び出した後に呼び出しました)。

申し訳ありませんが、今これをデバッグして、なぜ私がやっていたことがうまくいかなかったのか、なぜそれを変更するとうまくいったのかを理解する時間はありません。私が言ったように、これは将来誰かを助けるかもしれないと思っただけです。

0
Hamy

テキストを更新した後、ビューを再描画するためにinvalidateまたはpostInvalidateを呼び出していますか?カスタムビューの場合、描画コードにブレークポイントを設定して、それが確実に呼び出されるようにできますか?

UIスレッドを使用している場合は、 'invalidate'を呼び出すことができます。そうでない場合は、 'postInvalidate'を呼び出す必要があります。そうしないと、ビューが再描画されません。

0
haseman