Android: thiết lập kiểu xem theo chương trình


226

Đây là 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>

Làm thế nào để thiết lập stylethuộc tính theo chương trình?


Xem ở đây ['hồi đáp'] [1], điều này làm việc cho tôi. [1]: stackoverflow.com/a/5488652/2938493
Artificioo

Câu trả lời:


211

Về mặt kỹ thuật, bạn có thể áp dụng các kiểu lập trình, với các chế độ xem tùy chỉnh:

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

Hàm tạo một đối số là hàm được sử dụng khi bạn khởi tạo các khung nhìn theo chương trình.

Vì vậy, chuỗi hàm tạo này đến siêu có tham số kiểu.

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

Hoặc như @Dori chỉ ra một cách đơn giản:

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

34
Bạn chỉ có thể thực hiện việc này theo chương trình mà không cần mở rộng vì trình xây dựng 3 arg là công khai dù sao nhà phát
Dori

1
@Turbo, cả tài liệu và nhật thực sẽ cho bạn biết rằng : http://developer.android.com/reference/android/widget/LinearLayout.html#LinearLayout(android.content.Context, android.util.AttributeSet, int). Với linearLayout Cấp 11+ là bắt buộc.
TheOne

2
@Dori Bạn sẽ vượt qua điều AttributeSetgì?
Blundell

9
Nếu đó là TextView, bạn cần sử dụng setTextAppparent (R.style.small lòng) cho các thuộc tính ảnh hưởng đến văn bản (kích thước, màu sắc, v.v.)
Maragues

2
Tôi không biết tại sao cách tiếp cận đối số thứ 3 không hiệu quả. Tôi đã áp dụng cho Button. Cách tiếp cận @Benjamin Piette hoạt động tốt.
Youngjae

124

Điều gì làm việc cho tôi:

Button b = new Button(new ContextThemeWrapper(this, R.style.ButtonText), null, 0);
  • Sử dụng một ContextThemeWrapper

  • Sử dụng hàm tạo 3 đối số (sẽ không hoạt động nếu không có điều này)

Sử dụng phương thức của bạn hoạt động, nhưng tôi nhận được W / ResourceType Quá nhiều tham chiếu thuộc tính, dừng lại ở: 0x01010034. Bất kỳ cách giải quyết?
HaloMediaz

Tôi chưa bao giờ thấy vấn đề đó. Đó có thể là một vấn đề cụ thể của thiết bị, hoặc một cái gì đó liên quan đến phiên bản Android gần đây?
Benjamin Piette

11
QUAN TRỌNG! Phương pháp này không hoạt động, nhưng cũng sẽ thiết lập kiểu dáng cho mọi chế độ xem con nếu tạo Bố cục mới bằng ContextThemeWrapper.
aProperFox

@aProperFox bạn có thể giải thích rõ hơn? Với tôi hoạt động bằng cách thêm chỉ vào một nút. Bạn tham khảo một bố cục?
Gilian

1
@Gilian chính xác, nếu bạn sử dụng điều này trên chế độ xem ghép có một hoặc nhiều con, chúng sẽ có kiểu dáng giống như chế độ xem cha mẹ mà bạn đặt kiểu. Điều này có thể dẫn đến quá nhiều phần đệm hoặc lề trong chế độ xem bên trong và có thể khiến bạn phát điên nếu bạn không biết về nó :)
aProperFox

88

Cập nhật : Tại thời điểm trả lời câu hỏi này (giữa năm 2012, cấp độ API 14-15), việc đặt chế độ xem theo chương trình không phải là một tùy chọn (mặc dù có một số cách giải quyết không tầm thường) trong khi điều này đã được thực hiện sau API gần đây hơn phát hành. Xem câu trả lời của @ Blundell để biết chi tiết.

Trả lời:

Bạn chưa thể thiết lập kiểu xem theo lập trình, nhưng bạn có thể thấy chủ đề này hữu ích.


16
Không đúng. Xem câu trả lời của @ Blundell.
a.bertucci

31
Đối với một số tình huống (sử dụng TextView chẳng hạn), bạn có thể sử dụng textView.setTextAppearance(context, R.style.mystyle);. Theo tài liệu "Đặt màu văn bản, kích thước, kiểu, màu gợi ý và màu tô sáng từ tài nguyên TextAppparent đã chỉ định." developer.android.com/reference/android/widget/
Mạnh

4
api> 23; textView.setTextAppparent (R.style.m Phong);
akyol alican

1
Tôi đã đăng câu trả lời này hơn 4 năm trước @HaydenKai. và API đã thay đổi rất nhiều kể từ đó cho phép áp dụng các kiểu lập trình.
Korhan Ozturk

3
@KorhanOzturk đã đồng ý, nhưng trên SO với những câu hỏi như thế này có hoạt động, câu hỏi nên được mở lại và một câu trả lời mới được chấp nhận
HaydenKai

16

Đối với một Nút / TextView mới:

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

Đối với một ví dụ hiện có:

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

Đối với hình ảnh hoặc bố cục:

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

8

Nếu bạn muốn tiếp tục sử dụng XML (câu trả lời được chấp nhận không cho phép bạn làm) và đặt kiểu sau khi chế độ xem được tạo, bạn có thể sử dụng thư viện Paris hỗ trợ tập hợp con của tất cả các thuộc tính có sẵn.

Vì bạn đang tăng cường quan điểm của mình từ XML, bạn cần chỉ định một id trong bố cục:

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

Sau đó, khi bạn cần thay đổi kiểu lập trình, sau khi bố cục đã bị thổi phồng:

// 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);

Để biết thêm: danh sách các loại và thuộc tính chế độ xem được hỗ trợ (bao gồm nền, phần đệm, lề, v.v. và có thể dễ dàng được mở rộng) và hướng dẫn cài đặt với tài liệu bổ sung .

Tuyên bố miễn trừ trách nhiệm: Tôi là tác giả gốc của thư viện nói.


Đây có phải vẫn là một cách tiếp cận được đề xuất để sử dụng vào năm 2019?
IgorGanapolsky 22/03/19

1
@IgorGanapolsky afaik vâng! Tôi không biết cái nào tốt hơn.
Nathanael

Cảm ơn bạn @Nathanael đã cung cấp giải pháp này. Ngoài ra để là người duy trì nó với thuộc tính line_height mới nhất. Hãy tiếp tục phát huy! Thực sự hữu ích.
Guillem Roca

7

Bạn có thể áp dụng một phong cách cho hoạt động của mình bằng cách thực hiện:

super.setTheme( R.style.MyAppTheme );

hoặc mặc định của Android:

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

trong hoạt động của bạn, trước đây setContentView().


4
@sippy bạn có thể vui lòng để FOM thể hiện bản thân một cách tự do không? Anh ta không cần chỉnh sửa!
Mika

6

Không phải trong số các câu trả lời được cung cấp là chính xác.

Bạn có thể thiết lập phong cách theo chương trình.

Câu trả lời ngắn gọn là hãy xem http://grepcode.com/file/reposective.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/content/Context.java#435

Câu trả lời dài. Đây là đoạn trích của tôi để đặt kiểu được xác định tùy chỉnh theo chương trình cho chế độ xem của bạn:

1) Tạo một kiểu trong tệp kiểu tệp của bạn

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

Đừng quên xác định các thuộc tính tùy chỉnh của bạn trong tệp attrs.xml

Tệp attrsl.xml của tôi:

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

Lưu ý rằng bạn có thể sử dụng bất kỳ tên nào cho kiểu dáng của bạn (CustomWidget của tôi)

Bây giờ, hãy đặt kiểu cho tiện ích theo chương trình Đây là tiện ích đơn giản của tôi:

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));
}
}

bố trí:

<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>

Và cuối cùng là triển khai lớp 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;
}
}

Bạn có thể tìm thấy ví dụ hoạt động đầy đủ tại https://github.com/Defuera/setStylableProgramatically


13
Đây không phải là phong cách thực sự, nó chỉ là giả mạo bằng cách áp dụng / cài đặt các cài đặt đã lưu (vâng, thực ra đó là một số loại cài đặt được lưu trong tệp XML của bạn) trên Chế độ xem của bạn (ở đây bạn chỉ có 2 Chế độ xem cố định - bạn chắc chắn cần biết chúng Tới trước). Tất cả các phép thuật là trong applyphương pháp mà không có gì thú vị. Ý nghĩa thực sự của phong cách là nó tự động áp dụng một số phong cách trực quan trên tất cả các Chế độ xem được thêm động trong tương lai. Mã này ở đây tất nhiên không thể làm điều đó và không có gì là năng động ở đây, chúng ta cần phải biết những gì xem và đó tính / trường để đề ra.
Vua King

1
Tôi không ngại chỉ định các chế độ xem để áp dụng kiểu nào, nhưng giải pháp này có các thành phần kiểu được mã hóa cứng (ví dụ: textColor và spliterColor). Nó sẽ không tự động tìm tất cả các yếu tố được xác định trong phong cách và áp dụng chúng cho chế độ xem.
mũi

Liên kết bạn đã đăng không mở. Bạn có thể vui lòng đăng lại?
IgorGanapolsky 22/03/19

4

Đây là một câu hỏi khá cũ nhưng giải pháp hiệu quả với tôi bây giờ là sử dụng tham số thứ 4 của hàm tạo defStyleRes- nếu có sẵn .. trên chế độ xem ... để đặt kiểu

Các tác phẩm sau đây cho mục đích của tôi (kotlin):

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

3

Đây là ví dụ đơn giản của tôi, khóa là ContextThemeWrappertrình bao bọc, không có nó, kiểu của tôi không hoạt động và sử dụng hàm tạo ba tham số của View.

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

2

cách đơn giản là đi qua constructor

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

Một chút minh họa về cách sử dụng giải pháp này sẽ hữu ích.
IgorGanapolsky 22/03/19

1

Tôi không đề xuất sử dụng ContextThemeWrapper khi nó làm điều này:

Chủ đề được chỉ định sẽ được áp dụng trên đầu chủ đề của bối cảnh cơ sở.

Điều gì có thể làm cho kết quả không mong muốn trong ứng dụng của bạn. Thay vào đó, tôi đề xuất thư viện mới "paris" cho việc này từ các kỹ sư tại Airbnb:

https://github.com/airbnb/paris

Xác định và áp dụng các kiểu cho các chế độ xem Android theo chương trình.

Nhưng sau một thời gian sử dụng, tôi phát hiện ra rằng nó thực sự khá hạn chế và tôi đã ngừng sử dụng nó vì nó không hỗ trợ nhiều tài sản tôi cần ra khỏi hộp, vì vậy người ta phải kiểm tra và quyết định như mọi khi.


Giải thích cho bạn bè downvote của bạn ... Tôi đã mất một ngày rưỡi vì tôi đã sử dụng ContextThemeWrapper và nó áp dụng cho nền trắng chủ đề bối cảnh của tôi, sau đó đột nhiên tiện ích Chip từ thư viện tài liệu google bị sập, đoán tại sao ...
sập

Có phải thư viện Paris không sử dụng ContextThemeWrapper bên dưới?
IgorGanapolsky 22/03/19

@IgorGanapolsky thì không. Nó đọc kiểu XML và chuyển đổi nó thành các cuộc gọi phương thức tương ứng trên khung nhìn.
Nathanael

Nó thực sự khá hạn chế Tôi đã ngừng sử dụng nó vì nó không hỗ trợ nhiều tài sản tôi cần ...
Renetik 24/03/19

-1

Tôi đã sử dụng các khung nhìn được xác định trong XML trong Viewgroup tổng hợp của mình, thổi phồng chúng được thêm vào Viewgroup. Bằng cách này, tôi không thể tự động thay đổi kiểu nhưng tôi có thể thực hiện một số tùy chỉnh kiểu. Tổng hợp của tôi:

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);
}

}

và quan điểm của tôi trong xml nơi tôi có thể gán kiểu:

<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
Bạn đang tự động thiết lập phong cách ở đâu?
IgorGanapolsky 22/03/19

-3

Bạn có thể tạo xml chứa bố cục với kiểu mong muốn và sau đó thay đổi tài nguyên nền của chế độ xem của bạn, như thế này .


Bạn đang nói về một "phong cách" như trong Android, nhưng về "khía cạnh" của một nút. Điều này rất khác nhau.
Chúa Kitô
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.