RecyclerView 仅更新随机卡片视图文本大小的问题

Issues with RecyclerView only updating random cardview text size

我正在尝试在我的应用程序中实现动态文本大小选项。出于某种原因,回收商只是在我的卡片视图中随机更改文本大小,而不是将所有文本设置为所需的大小。当我滚动列表时,顶部的 cardview 文本将正确更改,但接下来的 3-4 将保持默认状态,并且随机向下列表另一个 cardview 文本将正确显示。当我向上滚动列表时,正确显示的卡片视图会随机变化。

主要Activity.....

// Dark Mode Menu
@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            mDrawer.openDrawer(GravityCompat.START);
            return true;
        case R.id.menu_night_mode_day:
            setNightMode(AppCompatDelegate.MODE_NIGHT_NO);
            break;
        case R.id.menu_night_mode_night:
            setNightMode(AppCompatDelegate.MODE_NIGHT_YES);
            break;
        case R.id.menu_night_mode_auto:
            setNightMode(AppCompatDelegate.MODE_NIGHT_AUTO);
            break;
        // Text Size Options
        case R.id.menu_text_size_small:
            setTextSize(18);
            break;
        case R.id.menu_text_size_medium:
            setTextSize(20);
            break;
        case R.id.menu_text_size_large:
            setTextSize(22);
            break;
    }
    return super.onOptionsItemSelected(item);
}

// Dark Mode Menu
private void setNightMode(@AppCompatDelegate.NightMode int nightMode) {
    AppCompatDelegate.setDefaultNightMode(nightMode);

    if (Build.VERSION.SDK_INT >= 11) {
        recreate();
    }
}

// Dynamic text size
private void setTextSize(int textSize) {
    TextView description = (TextView) findViewById(R.id.cardview_description);
    description.setTextSize(textSize);
    saveToPreferences(this, "THE_TEXT_SIZE", "" + textSize);
}

我的适配器....

public class MyPageAdapter extends Adapter<MyPageHolder> {

public List<MenuPageItems> datas;
private Activity activity;
public String dynamicTextSize;

public MyPageAdapter(Activity activity){
    datas = new ArrayList<>();
    this.activity = activity;
}

public void add(MenuPageItems dataModel){
    datas.add(dataModel);
}

public void add(MenuPageItems dataModel, int position){
    datas.add(position, dataModel);
}

public void addAll(List<MenuPageItems> menuPageItems){
    datas.addAll(menuPageItems);
}

@Override
public MyPageHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View v = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);
    return createViewHolder(v, viewType);
}

@Override
public void onBindViewHolder(MyPageHolder holder, int position) {
    holder.bind(datas.get(position), activity, position);
    dynamicTextSize = "20";
}

@Override
public int getItemCount() {
    return datas.size();
}

@Override
public int getItemViewType(int position){
    return datas.get(position).getViewResId();
}

public int searchViewTypePosition(int viewType){
    int i = 0;
    boolean found = false;
    while(i < datas.size() && !found){
        if(datas.get(i).getViewResId() == viewType){
            found = true;
            i--;
        }
        i++;
    }
    return i;
}

public MyPageHolder createViewHolder(View v, int viewType){
    return datas.get(searchViewTypePosition(viewType)).createViewHolder(v, activity, this);
}
}

持有人....

public abstract class MyPageHolder extends RecyclerView.ViewHolder{

protected final Activity activity;
protected MyPageAdapter adapter;
public TextView txtTitle, txtDescription, txtTheContent;
public ImageView imgImage;
public View view;

public MyPageHolder(View v, Activity activity, MyPageAdapter adapter) {
    super(v);
    this.activity = activity;
    this.adapter = adapter;

    imgImage = (ImageView) v.findViewById(R.id.cardview_image);
    txtTitle = (TextView) v.findViewById(R.id.cardview_title);
    txtDescription = (TextView) v.findViewById(R.id.cardview_description);
    view = (CardView) v.findViewById(R.id.card_view);

    view.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            /*/ this is where the magic happens when clicked /*/
        }
    });
}

public void bind(MenuPageItems dataModel, Activity activity, final int position) {
    final MenuPageItems m = (MenuPageItems)dataModel;
    imgImage.setImageResource(m.image);
    txtTitle.setText(m.title);
    txtDescription.setText(m.description);
    //txtTheContent.setText(m.theContent);

    view.setOnClickListener(new View.OnClickListener() {
        @Override public void onClick(View v){

            Intent cvIntent = new Intent(view.getContext(), EndpageActivity.class);

            // header image to pass to endpage activity
            cvIntent.putExtra("endpageHeader", m.image);

            // text to pass to endpage activity
            cvIntent.putExtra("endpageTitle", m.title);
            cvIntent.putExtra("endpageTheContent", m.theContent);
            view.getContext().startActivity(cvIntent);
        }
    });
}
}

我是否需要向我的适配器或取景器添加一些内容才能正确更新所有文本?

我想我明白了,但我根本没看到你在哪里设置文字大小,你说它在一些卡片中随机变化。

依我看,需要做的是在Holder的bind方法中设置大小。每次需要重新绘制卡片时都会执行此操作。您可以在 bind() 中读取共享首选项,但这非常低效,因为在滚动时会多次调用 holder 的绑定方法。你想避免持有人 bind()

内的任何多余工作

向适配器添加一个 dynamicTextSize 成员变量并设置值:

  1. 向适配器添加 setText/getText 尺寸,activity 可以在需要时设置它。
  2. 在适配器的构造函数中检索文本大小,然后覆盖 notifyDataSetChanged() 方法并在每次调用时再次提取值。然后调用 super.notifyDataSetChanged()

示例:

@Override
public void notifyDataSetChanged() {
   this.dynamicTextSize = // Pull value from shared preferences
   super.notifiyDataSetChanged();
}

我也没有看到传递到容器中的 dynamicTextSize 值。由于holder有adapter的引用,你可以在adapter中添加getTextSize()方法,holder调用adapter获取。

public MyPageHolder(View v, Activity activity, MyPageAdapter adapter) {
   ...
   this.dynamicTextSize = adapter.getTextSize()
}

最后,在 setTextSize() 方法中,您需要调用 adapter.notifyDataSetChanged() 来更新适配器。

更新 10/17

我试图在之前的 post 中添加一些细节。

主要Activity

// Dynamic text size
private void setTextSize(int textSize) {

    //  Add a call to set the text to the adapter's member variable:
    mAdapter.setTextSize(textSize);

    // I'm not sure what description is here...  I don't see what type the member is
    description.setTextSize(textSize);
    saveToPreferences(this, "THE_TEXT_SIZE", "" + textSize);
}

在您的适配器中,添加一个方法来设置和获取文本大小。 set会在mainactivity,文字大小改变的时候调用,get会在holder每次需要设置TextView的大小时调用。

public class MyPageAdapter extends Adapter<MyPageHolder> {

    ...
    public String dynamicTextSize;

    public void setTextSize(int textSize) {
       dynamicTextSize = textSize;
    }
    // This will be called by the holder
    public int getTextSize() {
       return dynamicTextSize;
    } 
    ...
}

在你的持有人中:

public abstract class MyPageHolder extends RecyclerView.ViewHolder{
    public void bind(MenuPageItems dataModel, Activity activity, final int position) {
        ...

        // Call into the adapter to get the text size.
        int textSize = adapter.getTextSize();
        txtDescription.setTextSize(textSize);
    }
}

更新 10/19

我只需稍加改动就可以让它正常工作。

  1. 在您的 MainActivity
  2. 中添加一个 getDynamicTextSize
  3. 在 MyPageAdapter 构造函数中添加对 get 的调用。

    public MyPageAdapter(Activity activity){
        datas = new ArrayList<>();
        this.activity = activity;
        dynamicTextSize = ((MainActivity)activity).getDynamicTextSize();
    }
    

虽然这确实有效,但几乎没有什么是它不能为您做的。

  1. 将您的片段始终作为 MainActivityactivity 的子级绑定,您可以通过接口解决此问题,但仍然不够漂亮。

  2. 不会在用户选择新的文本大小后立即更新当前 activity。由于 mainActivity 接受菜单事件,您需要通知任何活动的片段 is/are,文本设置已更改,然后在适配器上调用 notifiyDataSetChanged。

  3. 不设置自定义之外的文字大小RecyclerView。我看到你有一些片段不使用你的回收者视图。这些不会采取设置。菜单中的设置会让您认为应用程序中的所有文本都应该更改。

this post 中接受的回复似乎是调整整个应用程序文本大小的好方法。您应用中的某些更改几乎表明您已经看到了它。