테마 종속 Android 문자열


Answers

남성과 여성이 주제가 두 가지 인 응용 프로그램이 있다고 가정 해 봅시다. 테마는 단순히 사용자가 선호하는 취향에 호소하기 위해 색상 팔레트와 몇 가지 드로어 블을 변경합니다.

네가 뭔가하고있는 척 하는게 어때? 이는 성별에 따라 특정 색상 (예 : "핑크와 같은 소녀")을 연관시키는 디자인 안티 패턴입니다.

이것은 기술적 목적이 나쁘다는 것을 말하는 것은 아니며 단지 이것이 정말로 틀에 박힌 예입니다.

예를 들어, 해적 테마를 추가하고 "제출"이 "Arrrrgh"가 될 수 있습니다.

"Cancel"이 "Avast!"에 매핑되는 경우에만.

사용자가 선택할 수있는 테마를 통해 앱 전체에서 문자열을 어떻게 바꿀 수 있습니까?

그 끈이 어디에서 왔는지는 말하지 않았습니다. 문자열 리소스입니까? 데이터베이스 항목? 웹 서비스에서 검색하는 것은 무엇입니까? 다른 것?

나는 이들이 문자열 리소스라고 생각할 것입니다. 정의에 따르면, 문자열 당 N 개의 사본이 필요합니다 (주제 당 하나씩).

젠더 및 piratical 상태는 가능한 리소스 세트 한정자로 Android에서 추적하는 것이 아니므로 해당 문자열 리소스를 다른 리소스 세트에 포함시킬 수 없습니다. 다른 파일 (예 : res/values/strings_theme1.xml )에있을 수 있지만 파일 이름은 문자열의 리소스 식별자의 일부가 아닙니다. 따라서 어떤 문자열이 어떤 테마에 속해 있는지 추적하기 위해 접두어 / 접미사를 사용해야하는 경우가 있습니다 (예 : @string/btn_submit_theme1 ).

이러한 문자열이 런타임에 변경되지 않는 경우 - 레이아웃 리소스에있는 내용이 무엇이든간에 Chris Jenkins의 서예 라이브러리 에서 페이지를 가져올 수 있습니다. 그는 자신의 하위 클래스 인 LayoutInflater 를 사용하여 표준 XML 속성 중 일부를 오버로드하는 데 사용됩니다. 그의 경우, 그의 초점은 android:fontFamily 에 있으며, 여기서 그는 자산의 글꼴 파일에 대한 매핑을 지원합니다.

귀하의 경우, 당신은 android:text 오버로드 할 수 있습니다. 레이아웃 파일에서 실제 문자열을 가리키는 것이 아니라 원하는 문자열 리소스의 기본 이름이 될 수 있습니다 (예 : 실제 문자열이 @string/btn_submit_theme1 및 kin 인 경우). android:text="btn_submit" 가질 수 있음). LayoutInflater 하위 클래스는 해당 값을 가져 LayoutInflater 테마 이름 접미사를 추가하고 Resources getIdentifier() 를 사용하여 실제 문자열 리소스 ID를 조회 한 다음 테마에서 묶은 문자열을 가져옵니다.

이것에 대한 변형은 기본 이름을 android:text 대신에 android:tag 에 넣는 것입니다. android:text 는 GUI 디자인 등을 돕기 위해 실제 문자열 리소스 중 하나를 가리킬 수 있습니다. LayoutInflater 는 태그를 잡고 런타임에 올바른 문자열을 파생시키기 LayoutInflater 태그를 사용합니다.

테마 기반 문자열 리소스에서 가져온 다른 텍스트로 텍스트를 대체하려는 경우 적용 할 수있는 정적 유틸리티 메서드로 get-the-string-given-the-base-name 논리를 분리 할 수 ​​있습니다.

처음에는이 작업을 수행하는 데 약간의 시간이 걸리지 만 영향을받는 UI 위젯과 문자열의 수는 임의의 복잡성으로 확장됩니다. 정의한 새 문자열에 대해 모든 테마의 값을 추가해야한다는 점을 기억해야합니다 (맞춤 체크를 만들기위한 보너스 포인트 또는이를 확인하기위한 Gradle 작업).

Question

남성과 여성이 주제가 두 가지 인 응용 프로그램이 있다고 가정 해 봅시다. 테마는 단순히 사용자가 선호하는 취향에 호소하기 위해 색상 팔레트와 몇 가지 드로어 블을 변경합니다.

http://www.androidengineer.com/2010/06/using-themes-in-android-applications.html 에서 많은 도움을 주셔서 감사합니다.

그러나 이제는 앱으로 조금 더 귀여워지기를 원한다고 말하면서 색상과 드로어 블을 바꿀뿐만 아니라 줄을 바꾸기를 원합니다. 예를 들어, 해적 테마를 추가하고 "제출"이 "Arrrrgh"가 될 수 있습니다.

그래서, 내 기본적인 질문은 : 어떻게 응용 프로그램 내에서 사용자가 선택할 수있는 테마를 통해 문자열을 변경할 수 있습니까?

편집하다:

위로 만들기 : 응용 프로그램에는 12 개의 버튼과 32 개의 텍스트보기가 있습니다. 테마에 의존하고 싶습니다. 거대한 매핑이나 커스텀 attrs없이이 작업을 수행하고 싶습니다.

현재 솔루션 3 개 모두 작동합니다. 나는 그런 짐승이 있다는 것을 모릅니다.




그래, 실제로 유지 관리하고 코드 정리를 유지할 수있는 두 번째 옵션이 있지만 각 String에 대한 배열을로드하기 때문에 더 많은 리소스가 필요할 수 있습니다. 나는 그것을 벤치마킹하지 않았지만 그것을 다른 선택으로 제시 할 것이지만 너무 많은 테마 선택을 제공한다면 그것을 사용하지 않을 것이다.

public enum ThemeMode {
    NORMAL(0),
    PIRATE(1),
    NINJA(2);

    private int index;
    private ThemeMode(int index) {
        this.index = index;
    }

    public int getIndex() {
        return this.index;
    }
}
<resources>
    <!-- ALWAYS define strings in the correct order according to 
         the index values defined in the enum -->
    <string-array
        name="OK_ARRAY">
        <item>OK</item>
        <item>Yaarrrr!</item>
        <item>Hooaaaa!</item>
    </string-array>
    <string-array
        name="CANCEL_ARRAY">
        <item>Cancel</item>
        <item>Naarrrrr!</item>
        <item>Wha!</item>
    </string-array>
</resources>
public setButtonTexts(Context context, ThemeMode themeMode) {
    // buttons are instantiated elsewhere
    buttonOk.setText(context.getResources()
            .getStringArray(R.array.CANCEL_ARRAY)[themeMode.getIndex()]);
    buttonCancel.setText(context.getResources()
            .getStringArray(R.array.OK_ARRAY)[themeMode.getIndex()]);
}



그래서, 나는 이것을 테스트 할 기회가 없었지만, Locale의 파일을 읽는 것에서부터 자신의 위치를 ​​만들 수있는 것처럼 보입니다.

http://developer.android.com/reference/java/util/Locale.html

또 다른 도움

프로그래밍 방식으로 로케일 설정

약간의 조합이 나를 이끌고 있습니다.

Locale pirate = new Locale("Pirate");
Configuration config = new Configuration();
config.locale = pirate;
this.getActivity().getBaseContext().getResources()
   .updateConfiguration(config, 
    this.getActivity().getBaseContext().getResources().getDisplayMetrics());

나는 이것이 당신이 해적 일 때 사용하게 될 실제 유효 자원으로서 res / values-pirate / strings을 가질 수 있다고 믿는다. 재정의하지 않은 문자열이나 설정은 기본적으로 res / values ​​/ ...로 되돌아가 원하는 많은 테마에 대해이 작업을 수행 할 수 있습니다. 다시 작동한다고 가정합니다.




네, 그렇게 할 수 있습니다. 그리고 방법은 다음과 같습니다 : 먼저 theme 속성을 정의해야합니다.

<attr name="myStringAttr" format="string|reference" />

그런 다음 테마에이 줄을 추가하십시오.

<item name="myStringAttr">Yarrrrr!</item>

또는

<item name="myStringAttr">@string/yarrrrr</item>

그런 다음 XML 파일에서이 속성을 사용할 수 있습니다 ( @ 대신 ? 표시).

<TextView 
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="?attr/myStringAttr" />

또는 코드에서 다음과 같이하십시오.

public CharSequence resolveMyStringAttr(Context context) 
{
    Theme theme = context.getTheme();
    TypedValue value = new TypedValue();

    if (!theme.resolveAttribute(R.attr.myStringAttr, value, true)) {
        return null;
    }

    return value.string;
}



리소스는 마음에 단지 int 이므로 런타임에 여러 개의 리소스를 저장할 수 있으며 사용하는 동안 절차 적으로 대체 할 수 있습니다.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="OK_NORMAL">Okay</string>
    <string name="OK_PIRATE">Yaaarrrr!</string>
    <string name="OK_NINJA">Hooooaaa!</string>
</resources>
public enum ThemeMode {
    PIRATE,
    NINJA,
    NORMAL;
}
public class MyThemeStrings {
    public static int OK_PIRATE = R.string.OK_PIRATE;
    public static int OK_NINJA = R.string.OK_NINJA;
    public static int OK_NORMAL = R.string.OK_NORMAL;
}
public setOkButtonText(ThemeMode themeMode) {
    // buttonOk is instantiated elsewhere
    switch (themeMode) {
        case PIRATE:
            buttonOk.setText(MyThemeStrings.OK_PIRATE);
            break;
        case NINJA:
            buttonOk.setText(MyThemeStrings.OK_NINJA);
            break; 
        default:
            Log.e(TAG, "Unhandled ThemeMode: " + themeMode.name());
            // no break here so it flows into the NORMAL base case as a default
        case NORMAL:
            buttonOk.setText(MyThemeStrings.OK_NORMAL);
            break;
    }
}

모든 것을 작성한 후에 별도의 XML 파일을 통해이 모든 작업을 수행하는 것이 더 나은 방법 일 것입니다. 지금 살펴보고 내가 찾으면 두 번째 해결책을 써 보겠습니다.