2012-01-10 7 views
22

Tôi muốn cung cấp cho người dùng lựa chọn giữa một vài chủ đề khác nhau và tự hỏi liệu đây có phải là cách làm tốt hay không. Tôi đã làm một bài kiểm tra nhỏ với phương pháp này và nó đã làm việc, nhưng tôi nghĩ rằng có thể có những cách tốt hơn và nghĩ rằng nó có thể gây ra một số vấn đề sau này, vì vậy muốn hỏi.Thực hiện lựa chọn người dùng của chủ đề

Tôi đã nghĩ đến việc tạo bố cục khác nhau cho từng chủ đề và trong onCreate chỉ cần chuyển đổi phương thức setContentView(). Tôi sẽ tải một giá trị đã lưu SharedPreference (số nguyên) đầu tiên và tùy thuộc vào giá trị đó hiển thị bố cục tương ứng. Rõ ràng người dùng có thể thay đổi giá trị SharedPreference bằng một nút hoặc một cái gì đó.

Vì các bố cục này về cơ bản giống nhau nhưng với các màu khác nhau, tôi muốn sử dụng cùng một ID cho TextViews và các Chế độ xem khác trong mỗi tệp bố cục. Câu hỏi chính của tôi là điều này có gây ra vấn đề không?

Xin lỗi vì tường văn bản không có mã. Tôi chỉ muốn có một ý tưởng chung về thực hành tốt cho tình huống này. Cảm ơn trước.

Trả lời

37

Tôi thực sự có tính năng này trong ứng dụng của mình và bổ sung, tôi cho phép người dùng thay đổi chủ đề khi chạy. Khi đọc một giá trị từ các sở thích mất một thời gian, tôi nhận được một id chủ đề thông qua chức năng truy cập toàn cầu giữ giá trị được lưu trữ.

Như đã được chỉ ra - tạo một số chủ đề Android, sử dụng this guide. Bạn sẽ có ít nhất hai mục <style> trong tệp styles.xml của mình. Ví dụ:

<style name="Theme.App.Light" parent="@style/Theme.Light">...</style> 
<style name="Theme.App.Dark" parent="@style/Theme">...</style> 

Bây giờ, bạn phải áp dụng một trong các kiểu này cho hoạt động của mình. Tôi đang làm điều này trong phương pháp activitie của onCreate, trước bất kỳ cuộc gọi khác:

setTheme(MyApplication.getThemeId()); 

getThemeId là một phương pháp mà trả về cache ID chủ đề:

public static int getThemeId() 
{ 
    return themeId; 
} 

lĩnh vực này đã được cập nhật bởi một phương pháp khác:

public static void reloadTheme() 
{ 
    themeSetting = PreferenceManager.getDefaultSharedPreferences(context).getString("defaultTheme", "0"); 
    if(themeSetting.equals("0")) 
     themeId = R.style.Theme_Light; 
    else 
     themeId = R.style.Theme_Dark; 
} 

Được gọi bất cứ khi nào tùy chọn được thay đổi (và, khi khởi động khóa học). Hai phương pháp này nằm trong lớp MyApplication, mở rộng Application. Trình nghe thay đổi tùy chọn được mô tả ở cuối bài đăng này và nằm trong lớp hoạt động chính.

Điều cuối cùng và khá quan trọng - chủ đề được áp dụng, khi một hoạt động bắt đầu. Giả sử, bạn chỉ có thể thay đổi chủ đề trong màn hình ưu tiên và chỉ có một cách để đến đó, tức là chỉ từ một hoạt động chính, hoạt động này sẽ không được khởi động lại khi bạn thoát khỏi màn hình ưu tiên. đã sử dụng. Đây là bản vá cho rằng (khởi động lại hoạt động chính của bạn):

@Override 
protected void onResume() { 
    super.onResume(); 
    if(schduledRestart) 
    { 
     schduledRestart = false; 
     Intent i = getBaseContext().getPackageManager().getLaunchIntentForPackage(getBaseContext().getPackageName()); 
     i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 
     startActivity(i); 
    } 
} 

scheduledRestart là một biến boolean, bước đầu thiết lập là false. Đó là thiết lập là true khi chủ đề được thay đổi bởi người nghe này, mà cũng cập nhật ID chủ đề cache đã đề cập trước:

private class themeListener implements OnSharedPreferenceChangeListener{ 

    @Override 
    public void onSharedPreferenceChanged(SharedPreferences spref, String key) { 
     if(key.equals("defaultTheme") && !spref.getString(key, "0").equals(MyApplication.getThemeSetting())) 
     { 
      MyApplication.reloadTheme(); 
      schduledRestart = true; 
     } 
    } 


sp = PreferenceManager.getDefaultSharedPreferences(this); 

listener = new themeListener(); 
sp.registerOnSharedPreferenceChangeListener(listener); 

Nhớ giữ một tham chiếu đến đối tượng người nghe, nếu không nó sẽ Colleted rác (và sẽ không còn làm việc).

+0

Câu trả lời tuyệt vời, cảm ơn rất nhiều! –

+0

Tôi nghĩ rằng tôi có thể giải quyết mà không mở rộng ứng dụng, nhưng vấn đề là 'getApplicationInfo(). Chủ đề' không được cập nhật nếu tôi làm một' getApplication(). SetTheme (myThemeId) '... vì vậy có, cách của bạn là chính xác . – vault

+1

Có vẻ như có phương pháp khởi động lại hoạt động đơn giản hơn trong những ngày này: 'recreate' (https://developer.android.com/reference/android/app/Activity.html#recreate%28%29). – BlueMonkMN

2

Nó hoạt động nếu bạn làm theo cách này, và tôi không nghĩ rằng nó sẽ gây ra bất kỳ vấn đề nào, nhưng có vẻ như rất nhiều rắc rối (bạn phải nhân tất cả bố cục của mình với tất cả các chủ đề bạn muốn thêm Nếu sau này bạn muốn sửa đổi tài nguyên trong bố cục, bạn sẽ phải sửa đổi nó trong tất cả các chủ đề. Bạn chắc chắn sẽ quên một trong số đó)

Tại sao không sử dụng tính năng Styles and Themes của Android?

Họ có thể được áp dụng cho toàn bộ hoạt động một cách dễ dàng:

<activity android:theme="@style/my_theme"> 

Vì vậy, khi bạn phát hiện một sự thay đổi trong giá trị SharedPreferences bạn sử dụng (nút trên một hoạt động ưu tiên, hoặc một cái gì đó), bạn có thể chuyển sang phong cách . Hoặc tốt hơn, bạn có thể đặt kiểu để đọc giá trị tùy chọn của bạn khi chạy (khi tạo hoạt động) và áp dụng đúng kiểu/chủ đề phù hợp.

+0

Tôi sẽ đọc về tính năng Kiểu và chủ đề và thử làm theo cách đó, cảm ơn thông tin. Sẽ upvote bạn trong một giờ vì tôi đã sử dụng tất cả chúng lên ngày hôm qua: P –

2

Bạn cũng có thể thay đổi động chủ đề sử dụng:

ContextThemeWrapper w = new ContextThemeWrapper(this, <newTHEMEId>); 
getTheme().setTo(w.getTheme()); 

Trước onCreate cho từng hoạt động.