it-swarm.com.de

Theme/Style wird nicht angewendet, wenn der Inflater mit ApplicationContext verwendet wird

Ich habe ein Design, das textColor für TextView als rot definiert.

Ich verwende LayoutInflater, um TextView zu instanziieren. Das Problem ist, dass Stile nicht auf TextView angewendet werden, wenn der mit ApplicationContext erstellte Inflater verwendet wird - die Farbe ist nicht rot. Alles funktioniert gut, wenn LayoutInflater mit Aktivität erstellt wurde.

Warum passiert das und wie kann das behoben werden?

/res/values/styles.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="MyTheme">
        <item name="Android:textViewStyle">@style/MyTextView</item>
    </style>

    <style name="MyTextView" parent="@Android:style/Widget.TextView">
        <item name="Android:textColor">#f00</item>
    </style>
</resources>

AndroidManifest.xml:

<application 
    Android:icon="@drawable/icon" 
    Android:label="@string/app_name"
    Android:theme="@style/MyTheme"
    >

Code:

public class A extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test_a);

        final LayoutInflater goodInflater = getInflater((Activity)this); 
        final LayoutInflater badInflater = getInflater(getApplicationContext());
        final LinearLayout container = (LinearLayout)findViewById(R.id.container);

        findViewById(R.id.add_with_appContext).setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                add(container, badInflater); // Creates gray TextView
            }            
        });

        findViewById(R.id.add_with_activity).setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                add(container, goodInflater); // Creates red TextView
            }            
        });
    }

    private LayoutInflater getInflater(Context context) {
        return (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    private void add(LinearLayout container, LayoutInflater inflater) {
        inflater.inflate(R.layout.my_template, container, true);
    }
}

/res/layout/test_a.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="fill_parent"
    Android:layout_height="wrap_content"
    Android:orientation="vertical">

    <Button 
        Android:text="Add with AppContext" 
        Android:id="@+id/add_with_appContext" 
        Android:layout_width="wrap_content" 
        Android:layout_height="wrap_content" 
        />

    <Button 
        Android:text="Add with Activity" 
        Android:id="@+id/add_with_activity" 
        Android:layout_width="wrap_content" 
        Android:layout_height="wrap_content" 
        />

    <LinearLayout
        Android:id="@+id/container"
        Android:layout_width="fill_parent"
        Android:layout_height="wrap_content"
        Android:orientation="vertical"  
        />

</LinearLayout>

/res/layout/my_template.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="fill_parent" 
    Android:layout_height="wrap_content"
    >

    <TextView
        Android:id="@+id/text"
        Android:text="Some text..."
        Android:layout_width="fill_parent" 
        Android:layout_height="wrap_content"
    />

</LinearLayout>
43
alex2k8

Lösung # 1

Die Aufblasmethode akzeptiert das optionale Argument 'ViewGroup root':

public View inflate (int resource, ViewGroup root, boolean attachToRoot)

Wenn wir einen Wert als "root" -Parameter übergeben möchten, können wir ihn verwenden, um den "Aktivitätskontext" zu ermitteln, aus dem wir den korrekten LayoutInflater erhalten können:

ViewGroup root > activity context > LayoutInflater

Mein Code könnte also lauten:

private void add(LinearLayout container) {
    LayoutInflater inflater = getInflater(container.getContext());
    inflater.inflate(R.layout.my_template, container, true);
}

Lösung # 2

Ich habe gerade versucht, das Application Context-Design programmgesteuert zu setzen, und es funktioniert :

getApplicationContext().setTheme(R.style.MyTheme);

Ich denke, es war logisch, diesen Markup zu erwarten:

<application 
    Android:icon="@drawable/icon" 
    Android:label="@string/app_name"
    Android:theme="@style/MyTheme"
    >

um es automatisch einzustellen, tut es aber nicht.

50
alex2k8

Verwenden Sie niemals einen Anwendungskontext, um Ansichten aufzublähen, da das Styling in diesem Kontext nicht funktioniert. Verwenden Sie immer den Kontext einer Aktivität, wenn Sie mit Ansichten spielen. Die einzige Ausnahme ist, wenn Sie RemoteViews von einem Service erstellen müssen.

Weitere Informationen zu den verschiedenen Arten von Kontexten und ihren Möglichkeiten finden Sie in diesem ausgezeichneten Artikel .

33
BladeCoder

Normalerweise stelle ich dieses Problem beim Aufblasen einer benutzerdefinierten Ansicht fest. Ich persönlich tue das gleiche Thema der Aktivität in CustomView

public class CustomView extends ViewGroup{

public CustomView (Context context) {
    super(context);
    init(context);
}

public CustomView (Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context);
}

public CustomView (Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init(context);
}

@TargetApi(21)
public CustomView (Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
    init(context);
}

private void init(Context context) {
    LayoutInflater  mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View v = mInflater.inflate(R.layout.review_list_item, this, true);
    //rest of view initialization       
}   
}
0
abedfar