Duolingo的RTL ViewPager覆盖TabLayout字体

时间:2019-08-27 15:26:36

标签: android android-viewpager

我使用以下代码将TabLayout的标签设置为自定义字体:

Locale locale = Locale.getDefault();
if (locale.equals(new Locale("ar"))) {
    for (int i = 0; i < tabs.getTabCount(); i++) {
        @SuppressLint("InflateParams") TextView tv = (TextView)LayoutInflater.from(this).inflate(R.layout.custom_tabview,null);
        tv.setTypeface(Typeface.createFromAsset(getAssets(),"fonts/JannaLT-Regular.ttf"));
        Objects.requireNonNull(tabs.getTabAt(i)).setCustomView(tv);
    }
}

在我用RtlViewPager库替换XML中的ViewPager之前,此方法可以正常工作,因为Google出于某种原因仍未解决RTL布局中笨拙的错误刷卡操作。

<com.duolingo.open.rtlviewpager.RtlViewPager
    android:id="@+id/viewpager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"/>

之前:

<androidx.viewpager.widget.ViewPager
    android:id="@+id/viewpager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"/>

字体不想更改。通过调试,我可以知道if语句仍在执行,for循环以及其中的所有内容也是如此。但这并没有改变。由于某种原因,仅将其从ViewPager更改为RtlViewPager会导致TabLayout拒绝任何布局更改。甚至尝试将文本颜色设置为红色都无法正常工作。

2 个答案:

答案 0 :(得分:1)

我认为是因为RTLviewpager使用包装器作为原始适配器,然后在适配器连接到ViewPager时,它通知数据集两次更改。

因此,简单的方法是将自定义数据观察器连接到ViewPager适配器,并位于自定义TabLayout内,并且每当更改数据时,都再次应用自定义字体。

public class MyTabLayout extends TabLayout {


    @Nullable
    private PagerAdapter mPagerAdapter;

    private final DataSetObserver mDataSetObserver = new DataSetObserver() {
        @Override
        public void onChanged() {
            super.onChanged();
            notifyDataSetChanged();
        }
    };

    private final Runnable changeFontRunnable = () -> {
        /* ------ APPLY YOUR FONT HERE TO TAB LAYOUT  --------- */
    };

    public MyTabLayout(Context context) {
        super(context);
    }

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

    public MyTabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    @Override
    public void setupWithViewPager(@Nullable ViewPager viewPager) {
        super.setupWithViewPager(viewPager);

        if (viewPager != null && viewPager.getAdapter() != null) {
            unregisterObserver();
            mPagerAdapter = viewPager.getAdapter();
            registerObserver();
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        unregisterObserver();
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        unregisterObserver();
        registerObserver();
    }

    private void registerObserver() {
        if (mPagerAdapter != null) {
            mPagerAdapter.registerDataSetObserver(mDataSetObserver);
        }
    }

    private void unregisterObserver() {
        if (mPagerAdapter != null) {
            try {
                // may throw exception when the observer is not registered before
                mPagerAdapter.unregisterDataSetObserver(mDataSetObserver);
            } catch (IllegalStateException ignored) {}
        }
    }

    public void notifyDataSetChanged() {
        post(changeFontRunnable);
    }
}

答案 1 :(得分:0)

检查以下示例:

  

1)MainActivity.class

\n
  

2)CustomPagerAdapter.class

public class MainActivity extends AppCompatActivity {

private final String TAG = MainActivity.class.getSimpleName();
private RelativeLayout rl;
private TabLayout tabLayout;
private RtlViewPager viewPager;
private Button b;
private Context langResContext;
private String language;
private SharedPreferences sharedPreferences;
private final String ARABIC = "ar";
private final String ENGLISH = "en";

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

    sharedPreferences = getSharedPreferences(getResources().getString(R.string.prefs), MODE_PRIVATE);
    rl = (RelativeLayout) findViewById(R.id.rl);
    viewPager = (RtlViewPager) findViewById(R.id.viewpager);
    /**
     * get saved language and update ui
     */
    language = sharedPreferences.getString(getResources().getString(R.string.language),
            getResources().getString(R.string.language_default));
    b = (Button) findViewById(R.id.b);
    if (language.equals(getResources().getString(R.string.Arabic))) {
        language = getResources().getString(R.string.Arabic);
        langResContext = setLanguage(ARABIC, MainActivity.this);
        b.setText(getResources().getString(R.string.English));
    } else {
        language = getResources().getString(R.string.English);
        langResContext = setLanguage(ENGLISH, MainActivity.this);
        b.setText(getResources().getString(R.string.Arabic));
    }
    CustomPagerAdapter customPagerAdapter = new CustomPagerAdapter(getSupportFragmentManager(), 3, MainActivity.this,
            language, langResContext);
    viewPager.setAdapter(customPagerAdapter);
    tabLayout = (TabLayout) findViewById(R.id.tabLayout);
    viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
    b.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if (b.getText().toString().equals(getResources().getString(R.string.Arabic))) {
                language = getResources().getString(R.string.Arabic);
                langResContext = setLanguage(ARABIC, MainActivity.this);
                b.setText(getResources().getString(R.string.English));
            } else {
                language = getResources().getString(R.string.English);
                langResContext = setLanguage(ENGLISH, MainActivity.this);
                b.setText(getResources().getString(R.string.Arabic));
            }
            saveLanguage(language);
            onLanguageChanged(language, langResContext, true);
        }
    });
    onLanguageChanged(language, langResContext, false);
}


@TargetApi(Build.VERSION_CODES.KITKAT)
private void onLanguageChanged(String language, Context langResContext, boolean recreate) {
    if (language.equals(getResources().getString(R.string.Arabic))) {
        rl.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
    } else {
        rl.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
    }
    for (int i = 0; i < tabLayout.getTabCount(); i++) {
        tabLayout.getTabAt(i).setCustomView(null);
        @SuppressLint("InflateParams")
        TextView tv = (TextView) LayoutInflater.from(this).inflate(R.layout.custom_tabview, null);
        Objects.requireNonNull(tabLayout.getTabAt(i)).setCustomView(tv);
        if (language.equals(getResources().getString(R.string.Arabic))) {
            tv.setTypeface(Typeface.createFromAsset(getAssets(), "fonts/JannaLT-Regular.ttf"));
            tv.setTextColor(Color.BLUE);
        } else {
            tv.setTypeface(Typeface.createFromAsset(getAssets(), "fonts/SrabiScript.ttf"));
            tv.setTextColor(Color.GREEN);
        }
        switch (i) {
            case 0:
                tv.setText(langResContext.getResources().getString(R.string.page1));
                break;
            case 1:
                tv.setText(langResContext.getResources().getString(R.string.page2));
                break;
            case 2:
                tv.setText(langResContext.getResources().getString(R.string.page3));
                break;
        }
        CustomPagerAdapter customPagerAdapter = (CustomPagerAdapter) viewPager.getAdapter();
        if (customPagerAdapter != null) {
            customPagerAdapter.setLanguage(language, langResContext);
            CustomFragment customFragment = (CustomFragment) getSupportFragmentManager().findFragmentByTag(customPagerAdapter.getFragmentTag(i, viewPager.getId()));
            if (customFragment != null) {
                customFragment.setLanguage(language, langResContext);
                customFragment.applyLanguageChanges();
            }
        }
    }
    if(recreate){
        MainActivity.this.recreate();
    }
}

private void saveLanguage(String language) {
    SharedPreferences.Editor editor = sharedPreferences.edit();
    editor.putString(getResources().getString(R.string.language), language);
    editor.apply();
}

/**
 * https://stackoverflow.com/questions/2900023/change-app-language-programmatically-in-android
 *
 * Thanks to Zoe's Answer
 */
/**
 * * Full locale list: https://stackoverflow.com/questions/7973023/what-is-the-list-of-supported-languages-locales-on-android
 *
 * @param lang language code (e.g. en_US)
 * @return the context
 * PLEASE READ: This method can be changed for usage outside an Activity. Simply add a COntext to the arguments
 */
public Context setLanguage(String lang, Context c) {
    int API = Build.VERSION.SDK_INT;
    if (API >= 17) {
        return setLanguage17(lang, c);
    } else {
        return setLanguageLegacy(lang, c);
    }
}

/**
 * Set language for API 17
 *
 * @param lang
 * @param c
 * @return
 */
@TargetApi(17)
public Context setLanguage17(String lang, Context c) {
    Configuration overrideConfiguration = c.getResources().getConfiguration();
    Locale locale = new Locale(lang);
    Locale.setDefault(locale);
    overrideConfiguration.setLocale(locale);
    //the configuration can be used for other stuff as well
    Context context = createConfigurationContext(overrideConfiguration);//"local variable is redundant" if the below line is uncommented, it is needed
    //Resources resources = context.getResources();//If you want to pass the resources instead of a Context, uncomment this line and put it somewhere useful
    return context;
}

public Context setLanguageLegacy(String lang, Context c) {
    Resources res = c.getResources();
    // Change locale settings in the app.
    DisplayMetrics dm = res.getDisplayMetrics();//Utility line
    android.content.res.Configuration conf = res.getConfiguration();

    conf.locale = new Locale(lang);//setLocale requires API 17+ - just like createConfigurationContext
    Locale.setDefault(conf.locale);
    res.updateConfiguration(conf, dm);

    //Using this method you don't need to modify the Context itself. Setting it at the start of the app is enough. As you
    //target both API's though, you want to return the context as you have no clue what is called. Now you can use the Context
    //supplied for both things
    return c;
}

}

3)CustomFragment.class

public class CustomPagerAdapter extends FragmentPagerAdapter {

private int numberOfPages = 0;
private Context context;
private String language;
private Context langResContext;
private int[] color = new int[]{Color.RED, Color.MAGENTA, Color.GREEN};

public CustomPagerAdapter(FragmentManager fm, int numberOfPages, Context context,
                          String language, Context langResContext) {
    super(fm);
    this.numberOfPages = numberOfPages;
    this.context = context;
    this.language = language;
    this.langResContext = langResContext;
}

@Override
public Fragment getItem(int position) {
    CustomFragment customFragment = new CustomFragment(context,
            language, langResContext);
    Bundle extras = new Bundle();
    extras.putInt(CustomFragment.NUMBER, position);
    extras.putInt(CustomFragment.COLOR, color[position]);
    customFragment.setArguments(extras);
    return customFragment ;
}

@Override
public int getCount() {
    return this.numberOfPages;
}

public String getFragmentTag(int pos, int vpId) {
    return "android:switcher:" + vpId + ":" + pos;
}

public void setLanguage(String language, Context langResContext) {
    this.language = language;
    this.langResContext = langResContext;
}
}
  

4)activity_main.xml

    

public class CustomFragment extends Fragment {

private int number = 0;
private int color = Color.BLACK;

public static final String NUMBER = "number";
public static final String COLOR = "color";
public static final String LANGUAGE = "language";

private Context context;
private String language;
private Context langResContext;

public CustomFragment(Context context, String language, Context langResContext) {
    super();
    this.context = context;
    this.langResContext = langResContext;
    this.language = language;

}

public CustomFragment() {
    super();
}

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View layout = (View) inflater.inflate(R.layout.custom_fragment, container, false);
    return layout;
}

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    if (getArguments() != null) {
        Bundle extra = getArguments();
        number = extra.getInt(NUMBER, 0);
        color = extra.getInt(COLOR, Color.BLACK);
    }
    applyLanguageChanges();
}

public void applyLanguageChanges() {
    View view = getView();
    Context langResContext  = this.langResContext != null ? this.langResContext : this.context;
    if (getArguments() != null && view != null) {
        Bundle extra = getArguments();
        number = extra.getInt(NUMBER, 0);
        color = extra.getInt(COLOR, Color.WHITE);
        TextView tv = (TextView) view.findViewById(R.id.tv);
        String text = "0";
        switch (number) {
            case 0:
                text = langResContext.getResources().getString(R.string.page1);
                break;
            case 1:
                text = langResContext.getResources().getString(R.string.page2);
                break;
            case 2:
                text = langResContext.getResources().getString(R.string.page3);
                break;
        }
        tv.setText(text);
        tv.setBackgroundColor(this.color);
    }
}

public void setLanguage(String language, Context langResContext){
    this.language = language;
    this.langResContext = langResContext;
}

}
  

5)custom_fragment.xml

<com.google.android.material.tabs.TabLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/tabLayout"
    android:layout_alignParentTop="true"
    android:background="@color/colorPrimary"
    app:tabSelectedTextColor="@android:color/white"
    app:tabTextColor="@android:color/black">

    <com.google.android.material.tabs.TabItem
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/page1"
        android:text="@string/page1">
    </com.google.android.material.tabs.TabItem>

    <com.google.android.material.tabs.TabItem
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/page2"
        android:text="@string/page2">
    </com.google.android.material.tabs.TabItem>

    <com.google.android.material.tabs.TabItem
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/page3"
        android:text="@string/page3">
    </com.google.android.material.tabs.TabItem>

</com.google.android.material.tabs.TabLayout>

<com.duolingo.open.rtlviewpager.RtlViewPager
    android:id="@+id/viewpager"
    android:layout_below="@id/tabLayout"
    android:layout_width="match_parent"
    android:layout_above="@id/b"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    android:layout_height="match_parent"/>

<Button
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:text="@string/English"
    android:id="@+id/b">
</Button>

</RelativeLayout>
  

6)custom_tabview.xml

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

<TextView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:textSize="45sp"
    android:gravity="center"
    android:id="@+id/tv"
    android:textColor="@android:color/white"
    android:text="Page">
</TextView>

</LinearLayout>
  

7)strings.xml(英语)

<?xml version="1.0" encoding="utf-8"?>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/tv"
android:gravity="center"
xmlns:android="http://schemas.android.com/apk/res/android">
</TextView>
  

8)strings.xml(阿拉伯语)

    

<resources>
<string name="page1">Page 1</string>
<string name="page2">Page 2</string>
<string name="page3">Page 3</string>

<string name="prefs">prefs</string>
<string name="language">language_pref</string>
<string name="language_default">English</string>
<string name="English">English</string>
<string name="Arabic">العربية</string>

</resources>
  

9)输出

output