Android: ตั้งค่าลักษณะมุมมองโดยทางโปรแกรม


226

นี่คือ XML:

<RelativeLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    style="@style/LightStyle"
    android:layout_width="fill_parent"
    android:layout_height="55dip"
    android:clickable="true"
    android:orientation="horizontal" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal" />

</RelativeLayout>

วิธีการตั้งค่าstyleคุณลักษณะทางโปรแกรม?


ดูที่นี่ ['การตอบสนอง'] [1] สิ่งนี้ใช้ได้สำหรับฉัน [1]: stackoverflow.com/a/5488652/2938493
Artificioo

คำตอบ:


211

ในทางเทคนิคคุณสามารถใช้สไตล์โดยทางโปรแกรมด้วยมุมมองที่กำหนดเองต่อไป:

private MyRelativeLayout extends RelativeLayout {
  public MyRelativeLayout(Context context) {
     super(context, null, R.style.LightStyle);
  }
}

ตัวสร้างอาร์กิวเมนต์ตัวเดียวคือสิ่งที่ใช้เมื่อคุณสร้างอินสแตนซ์ของมุมมองโดยทางโปรแกรม

เชื่อมโยงคอนสตรัคเตอร์นี้กับซุปเปอร์ที่ใช้พารามิเตอร์สไตล์

RelativeLayout someLayout = new MyRelativeLayout(new ContextThemeWrapper(this,R.style.RadioButton));

หรือตามที่ @Dori ชี้ให้เห็นอย่างง่ายๆ:

RelativeLayout someLayout = new RelativeLayout(new ContextThemeWrapper(activity,R.style.LightStyle));

34
คุณสามารถทำแบบนี้ได้โดยไม่ต้องขยายเนื่องจากตัวสร้าง 3 AR เป็นแบบสาธารณะอย่างไรก็ตามdeveloper.android.com/reference/android/widget/… , android.util.AttributeSet, int)
Dori

1
@Turbo http://developer.android.com/reference/android/widget/LinearLayout.html#LinearLayout(android.content.Context, android.util.AttributeSet, int)ทั้งเอกสารและคราสควรจะบอกคุณว่า ด้วย LinearLayout ระดับ 11+ เป็นสิ่งจำเป็น
TheOne

2
@Dori คุณจะผ่านAttributeSetอะไรไป
Blundell

9
หากเป็น TextView คุณต้องใช้ setTextAppearance (R.style.small_text) สำหรับแอตทริบิวต์เหล่านั้นที่มีผลต่อข้อความ (ขนาดสี ฯลฯ )
Maragues

2
ฉันไม่มีความคิดว่าเหตุใดวิธีการโต้แย้ง 3 ไม่ทำงาน Buttonผมนำไปใช้กับ วิธีการ @Benjamin Piette ทำงานได้ดี
ยองแจ

124

อะไรที่เหมาะกับฉัน:

Button b = new Button(new ContextThemeWrapper(this, R.style.ButtonText), null, 0);
  • ใช้ ContextThemeWrapper

และ

  • ใช้คอนสตรัคเตอร์ 3 ข้อโต้แย้ง (จะไม่ทำงานหากไม่มีสิ่งนี้)

การใช้วิธีการของคุณใช้งานได้ แต่ฉันได้รับ W / ResourceType references มีการอ้างอิงแอตทริบิวต์มากเกินไปหยุดที่: 0x01010034 วิธีแก้ปัญหาใด ๆ
HaloMediaz

ฉันไม่เคยเห็นปัญหานี้ นั่นอาจเป็นปัญหาเฉพาะอุปกรณ์หรือบางอย่างที่เกี่ยวข้องกับ Android เวอร์ชันล่าสุด?
Benjamin Piette

11
สำคัญ! วิธีการนี้จะไม่ทำงาน แต่จะกำหนดจัดแต่งทรงผมสำหรับทุกมุมมองของเด็กเช่นกันถ้าการสร้างรูปแบบใหม่กับ ContextThemeWrapper
aProperFox

@aProperFox คุณสามารถอธิบายได้ดีขึ้นหรือไม่ กับฉันทำงานด้วยการเพิ่มเพียงปุ่ม คุณอ้างถึงเลย์เอาต์หรือไม่?
Gilian

1
@Gilian แน่นอนถ้าคุณใช้สิ่งนี้ในมุมมองผสมที่มีลูกหนึ่งคนขึ้นไปพวกเขาจะได้รับการจัดแต่งทรงผมเช่นเดียวกับมุมมองหลักที่คุณกำหนดสไตล์ไว้ สิ่งนี้อาจทำให้เกิดช่องว่างภายในหรือขอบมากเกินไปในมุมมองด้านในและสามารถทำให้คุณเสียสติได้หากคุณไม่ทราบ :)
aProperFox

88

อัปเดต : ในเวลาที่ตอบคำถามนี้ (กลางปี ​​2012, ระดับ API 14-15) การตั้งค่ามุมมองโดยทางโปรแกรมไม่ใช่ตัวเลือก (แม้ว่าจะมีวิธีแก้ไขปัญหาเล็กน้อยที่ไม่น่าสนใจ) ในขณะที่สิ่งนี้ได้เกิดขึ้นหลังจาก API ล่าสุด เผยแพร่ ดูคำตอบของ @ Blundell สำหรับรายละเอียด

คำตอบเก่า:

คุณไม่สามารถตั้งค่าลักษณะของมุมมองโดยทางโปรแกรม แต่คุณอาจพบว่าเธรดนี้มีประโยชน์


16
ไม่จริง. ดูคำตอบของ @ Blundell
a.bertucci

31
สำหรับบางสถานการณ์ (โดยใช้ TextView เป็นต้น) คุณสามารถtextView.setTextAppearance(context, R.style.mystyle);ใช้ได้ อ้างอิงจาก doc "ตั้งค่าสีข้อความขนาดสไตล์สีคำใบ้และสีไฮไลต์จากทรัพยากร TextAppearance ที่ระบุ" developer.android.com/reference/android/widget/… , int)
Rogel Garcia

4
api> 23; textView.setTextAppearance (R.style.mystyle);
alican akyol

1
ฉันโพสต์คำตอบนี้เมื่อ 4 ปีที่แล้ว @HaydenKai และ API มีการเปลี่ยนแปลงอย่างมากนับตั้งแต่เปิดใช้งานการใช้รูปแบบโดยทางโปรแกรม
Korhan Ozturk

3
@KorhanOzturk เห็นด้วย แต่สำหรับ SO ด้วยคำถามเช่นนี้ที่มีกิจกรรมคำถามควรเปิดใหม่และได้รับคำตอบใหม่
HaydenKai

16

สำหรับปุ่ม / TextView ใหม่:

Button mMyButton = new Button(new ContextThemeWrapper(this, R.style.button_disabled), null, 0);

สำหรับอินสแตนซ์ที่มีอยู่:

mMyButton.setTextAppearance(this, R.style.button_enabled);

สำหรับรูปภาพหรือเลย์เอาต์:

Image mMyImage = new ImageView(new ContextThemeWrapper(context, R.style.article_image), null, 0);

8

หากคุณต้องการใช้ XML ต่อไป (ซึ่งคำตอบที่ยอมรับไม่อนุญาตให้คุณทำ) และตั้งค่าสไตล์หลังจากสร้างมุมมองแล้วคุณสามารถใช้ห้องสมุดปารีสซึ่งรองรับชุดย่อยของแอตทริบิวต์ที่มีอยู่ทั้งหมด

เนื่องจากคุณขยายมุมมองของคุณจาก XML คุณจะต้องระบุ ID ในโครงร่าง:

<RelativeLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/my_styleable_relative_layout"
    style="@style/LightStyle"
    ...

จากนั้นเมื่อคุณต้องการเปลี่ยนสไตล์โดยทางโปรแกรมหลังจากเลย์เอาต์ที่สูงเกินจริง:

// Any way to get the view instance will do
RelativeLayout myView = findViewById(R.id.my_styleable_relative_layout);

// This will apply all the supported attribute values of the style
Paris.style(myView).apply(R.style.LightStyle);

สำหรับข้อมูลเพิ่มเติม: รายการประเภทสนับสนุนมุมมองและแอตทริบิวต์ (รวมถึงพื้นหลังการขยายขอบ ฯลฯ และสามารถขยายได้อย่างง่ายดาย) และคำแนะนำการติดตั้งกับเอกสารเพิ่มเติม

คำเตือน: ฉันเป็นผู้เขียนต้นฉบับของห้องสมุดดังกล่าว


นี่ยังเป็นแนวทางที่แนะนำให้ใช้ในปี 2019 หรือไม่?
IgorGanapolsky

1
@IgorGanapolsky afaik ใช่! ฉันไม่รู้เรื่องที่ดีกว่านี้อีกแล้ว
นาธานาเอล

ขอบคุณ @Nathanael ที่ให้บริการโซลูชั่นนี้ นอกจากนี้สำหรับการเป็นผู้ดูแลด้วยคุณลักษณะ line_height ล่าสุด ดีแล้วทำต่อไป! มีประโยชน์จริงๆ
Guillem Roca

7

คุณสามารถใช้สไตล์กับกิจกรรมของคุณโดยทำ:

super.setTheme( R.style.MyAppTheme );

หรือ Android เริ่มต้น:

super.setTheme( android.R.style.Theme );

setContentView()ในกิจกรรมของคุณก่อน


4
@ โปรดอย่าปล่อยให้ FOM แสดงความเป็นอิสระของตัวเองได้ไหม? เขาไม่ต้องการการแก้ไข!
มิกะ

6

ไม่ใช่คำตอบที่ให้ถูกต้อง

คุณสามารถกำหนดรูปแบบโดยทางโปรแกรม

คำตอบสั้น ๆ คือดูที่http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/content/Context.java#435

คำตอบที่ยาว ต่อไปนี้เป็นตัวอย่างข้อมูลของฉันเพื่อตั้งค่าสไตล์ที่กำหนดเองตามมุมมองของคุณ:

1) สร้างสไตล์ในไฟล์ styles.xml ของคุณ

 <style name="MyStyle">
    <item name="customTextColor">#39445B</item>
    <item name="customDividerColor">#8D5AA8</item>
</style>

อย่าลืมกำหนดแอตทริบิวต์ที่กำหนดเองของคุณในไฟล์ attrs.xml

ไฟล์ attrsl.xml ของฉัน:

<declare-styleable name="CustomWidget">
    <attr name="customTextColor" format="color" />
    <attr name="customDividerColor" format="color" />
</declare-styleable>

แจ้งให้ทราบว่าคุณสามารถใช้ชื่อใด ๆ สำหรับสไตล์ของคุณ (CustomWidget ของฉัน)

ตอนนี้ให้ตั้งค่าสไตล์วิดเจ็ตโดยทางโปรแกรมนี่คือวิดเจ็ตง่ายๆของฉัน:

public class StyleableWidget extends LinearLayout {

private final StyleLoader styleLoader = new StyleLoader();

private TextView textView;
private View divider;

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

private void init() {
    inflate(getContext(), R.layout.widget_styleable, this);
    textView = (TextView) findViewById(R.id.text_view);
    divider = findViewById(R.id.divider);
    setOrientation(VERTICAL);
}

protected void apply(StyleLoader.StyleAttrs styleAttrs) {
    textView.setTextColor(styleAttrs.textColor);
    divider.setBackgroundColor(styleAttrs.dividerColor);
}

public void setStyle(@StyleRes int style) {
    apply(styleLoader.load(getContext(), style));
}
}

รูปแบบ:

<TextView
    android:id="@+id/text_view"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="22sp"
    android:layout_gravity="center"
    android:text="@string/styleble_title" />

<View
    android:id="@+id/divider"
    android:layout_width="match_parent"
    android:layout_height="1dp"/>

</merge>

และการใช้คลาส StyleLoader ในที่สุด

public class StyleLoader {

public StyleLoader() {

}

public static class StyleAttrs {
    public int textColor;
    public int dividerColor;
}

public StyleAttrs load(Context context, @StyleRes int styleResId) {
    final TypedArray styledAttributes = context.obtainStyledAttributes(styleResId, R.styleable.CustomWidget);
    return load(styledAttributes);
}

@NonNull
private StyleAttrs load(TypedArray styledAttributes) {
    StyleAttrs styleAttrs = new StyleAttrs();
    try {
        styleAttrs.textColor = styledAttributes.getColor(R.styleable.CustomWidget_customTextColor, 0);
        styleAttrs.dividerColor = styledAttributes.getColor(R.styleable.CustomWidget_customDividerColor, 0);
    } finally {
        styledAttributes.recycle();
    }
    return styleAttrs;
}
}

คุณสามารถดูตัวอย่างการทำงานได้อย่างสมบูรณ์ที่https://github.com/Defuera/SetStylableProgramatically


13
นี้ไม่ได้เป็นรูปแบบที่แท้จริงมันเป็นแค่ของปลอมโดยการใช้ / การตั้งค่าการตั้งค่าที่บันทึกไว้ (ใช่มันเป็นความจริงชนิดของการตั้งค่าบางบันทึกไว้ในไฟล์ XML ของคุณ) คุณผู้ชม (ที่นี่คุณจะมีเพียง 2 คงมุมมอง - และคุณก็ต้องรู้ว่าพวกเขา ก่อน) เวทมนตร์ทั้งหมดอยู่ในapplyวิธีการที่ไม่น่าสนใจ ความหมายที่แท้จริงของสไตล์คือการใช้สไตล์ภาพโดยอัตโนมัติในการเพิ่ม Views แบบไดนามิกในอนาคต รหัสนี้ที่นี่แน่นอนไม่สามารถทำเช่นนั้นและมีอะไรที่แบบไดนามิกที่นี่เราต้องรู้ว่าสิ่งที่ผู้ชมและซึ่งคุณสมบัติ / สาขาไปยังชุด
King King

1
ฉันไม่รังเกียจที่จะระบุว่ามุมมองใดที่จะนำสไตล์ไปใช้ แต่โซลูชันนี้มีองค์ประกอบของสไตล์ที่กำหนดค่าตายตัว (เช่น textColor และ dividerColor) มันจะไม่ค้นหาองค์ประกอบทั้งหมดที่กำหนดในสไตล์และนำไปใช้กับมุมมอง
nasch

ลิงค์ที่คุณโพสต์ไม่เปิด คุณช่วยกรุณาโพสต์ใหม่ได้ไหม?
IgorGanapolsky

4

นี่เป็นคำถามที่ค่อนข้างเก่า แต่วิธีแก้ปัญหาที่ใช้ได้ผลสำหรับฉันตอนนี้คือการใช้พารามิเตอร์ตัวที่ 4 ของ constructor defStyleRes- ถ้ามี .. ในมุมมอง ... เพื่อกำหนดรูปแบบ

งานต่อไปนี้เพื่อวัตถุประสงค์ของฉัน (kotlin):

val textView = TextView(context, null, 0, R.style.Headline1)

3

นี่คือตัวอย่างง่ายๆของฉันกุญแจคือContextThemeWrapperเสื้อคลุมไม่มีสไตล์ของฉันไม่ทำงานและใช้ตัวสร้างพารามิเตอร์สามตัวของมุมมอง

ContextThemeWrapper themeContext = new ContextThemeWrapper(this, R.style.DefaultLabelStyle);
TextView tv = new TextView(themeContext, null, 0);
tv.setText("blah blah ...");
layout.addView(tv);

2

วิธีง่ายๆคือการผ่านคอนสตรัค

RadioButton radioButton = new RadioButton(this,null,R.style.radiobutton_material_quiz);

ภาพประกอบเพิ่มเติมเล็กน้อยเกี่ยวกับวิธีใช้โซลูชันนี้จะเป็นประโยชน์
IgorGanapolsky

1

ฉันไม่เสนอให้ใช้ ContextThemeWrapper เช่นนี้:

ชุดรูปแบบที่ระบุจะถูกนำไปใช้ด้านบนของชุดรูปแบบของบริบทฐาน

สิ่งที่สามารถสร้างผลลัพธ์ที่ไม่พึงประสงค์ในใบสมัครของคุณ ฉันขอเสนอ "ปารีส" ห้องสมุดใหม่สำหรับสิ่งนี้จากวิศวกรที่ Airbnb:

https://github.com/airbnb/paris

กำหนดและใช้สไตล์กับมุมมอง Android โดยทางโปรแกรม

แต่หลังจากใช้ไปสักพักฉันพบว่ามันค่อนข้าง จำกัด จริง ๆ และฉันหยุดใช้มันเพราะมันไม่รองรับคุณสมบัติมากมายที่ฉันต้องการออกนอกกล่องดังนั้นเราต้องตรวจสอบและตัดสินใจเช่นเคย


อธิบายเพื่อน downvote ของคุณ ... ฉันทำหายไปหนึ่งวันครึ่งเพราะฉันใช้ ContextThemeWrapper และมันนำไปใช้กับพื้นหลังสีขาวตามบริบทของธีมของฉันจากนั้นทันใดนั้นวิดเจ็ตชิปจากห้องสมุดวัสดุของ Google ล้มเหลวเดาว่าทำไม ...
Renetik

ห้องสมุดปารีสไม่ใช้ContextThemeWrapperข้างล่างใช่ไหม
IgorGanapolsky

@IgorGanapolsky มันไม่ได้ มันอ่านสไตล์ XML และแปลงเป็นการเรียกใช้วิธีการที่สอดคล้องกันในมุมมอง
นาธานาเอล

จริงๆแล้วมันค่อนข้าง จำกัด ฉันหยุดใช้มันเพราะมันไม่รองรับคุณสมบัติมากมายที่ฉันต้องการ ...
Renetik

-1

ฉันใช้มุมมองที่กำหนดใน XML ใน ViewGroup ของฉันแบบผสมเพิ่มจำนวนให้กับ Viewgroup วิธีนี้ฉันไม่สามารถเปลี่ยนสไตล์ได้ แต่สามารถปรับแต่งสไตล์ได้ คอมโพสิตของฉัน:

public class CalendarView extends LinearLayout {

private GridView mCalendarGrid;
private LinearLayout mActiveCalendars;

private CalendarAdapter calendarAdapter;

public CalendarView(Context context) {
    super(context);

}

public CalendarView(Context context, AttributeSet attrs) {
    super(context, attrs);

}

@Override
protected void onFinishInflate() {
    super.onFinishInflate();
    init();
}

private void init() {
    mCalendarGrid = (GridView) findViewById(R.id.calendarContents);
    mCalendarGrid.setNumColumns(CalendarAdapter.NUM_COLS);

    calendarAdapter = new CalendarAdapter(getContext());
    mCalendarGrid.setAdapter(calendarAdapter);
    mActiveCalendars = (LinearLayout) findViewById(R.id.calendarFooter);
}

}

และมุมมองของฉันใน xml ที่ฉันสามารถกำหนดสไตล์:

<com.mfitbs.android.calendar.CalendarView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/calendar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:orientation="vertical"
>

<GridView
    android:id="@+id/calendarContents"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

<LinearLayout
    android:id="@+id/calendarFooter"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    />


1
คุณตั้งค่าสไตล์อยู่ที่ไหน
IgorGanapolsky

-3

คุณสามารถสร้าง XML ที่มีรูปแบบที่มีรูปแบบที่ต้องการแล้วเปลี่ยนทรัพยากรพื้นหลังของมุมมองของคุณเช่นนี้


คุณกำลังพูดถึงเรื่อง "สไตล์" ใน Android แต่เกี่ยวกับ "มุมมอง" ของปุ่ม มันแตกต่างกันมาก
คริสต์
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.