Проблемы с RecyclerView, обновляющим только случайный размер текста карты

Я пытаюсь реализовать параметр динамического размера текста в своем приложении. По какой-то причине переработчик только случайным образом меняет размер текста в моих карточках вместо того, чтобы устанавливать для всего текста желаемый размер. Когда я прокручиваю список, верхний текст карты будет меняться правильно, но следующие 3-4 останутся по умолчанию, а случайным образом вниз по списку будет отображаться другой текст карты. когда я прокручиваю список вверх, правильно отображаемый вид карты будет меняться случайным образом.

Основная деятельность....

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

Нужно ли мне что-то добавлять в мой адаптер или вьюхолдер, чтобы правильно обновить весь текст?


person The Green Bastard    schedule 13.10.2016    source источник
comment
Было бы лучше, если бы мы могли увидеть ваши методы bindViewHolder() и createViewHolder() для адаптера.   -  person Gary Bak    schedule 13.10.2016
comment
Я добавил весь свой код адаптера и вьюхолдера. благодаря.   -  person The Green Bastard    schedule 13.10.2016


Ответы (1)


Кажется, я понял, но я вообще не вижу, где вы устанавливаете размер текста, вы сказали, что он меняется в некоторых карточках случайным образом.

Как я понимаю, что нужно сделать, так это установить размер в методе привязки холдера. Это выполняется каждый раз, когда карту необходимо перерисовать. Вы можете прочитать общие настройки внутри bind(), но это ужасно неэффективно, поскольку метод привязки держателя будет вызываться много раз при прокрутке. Вы хотите избежать лишней работы внутри привязки держателей().

Добавьте переменную-член dynamicTextSize в адаптер и установите значение одним из следующих способов:

  1. Добавьте к адаптеру размер setText/getText, и действие сможет установить его при необходимости.
  2. Получите размер текста внутри конструктора адаптера, а затем переопределите метод notifyDataSetChanged() и снова извлекайте значение при каждом вызове. Затем позвоните super.notifyDataSetChanged()

Пример:

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

Чего я также не вижу, так это значения dynamicTextSize, передаваемого в держатель. Поскольку держатель имеет ссылку на адаптер, вы можете добавить к адаптеру метод getTextSize(), после чего держатель может вызвать адаптер, чтобы получить его.

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

Наконец, в методе setTextSize() вам нужно будет вызвать adapter.notifyDataSetChanged() для обновления адаптера.

Обновление от 17 октября

Я попытался добавить некоторые детали к предыдущему сообщению.

Основное действие

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

В вашем адаптере добавьте метод для установки и получения размера текста. Набор будет вызываться основным действием при изменении размера текста, а get вызывается держателем каждый раз, когда ему нужно установить размер 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);
    }
}

Обновление от 19 октября

Я смог заставить его работать с небольшим изменением.

  1. Добавьте getDynamicTextSize в свою MainActivity
  2. Добавьте вызов get из конструктора MyPageAdapter.

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

Хотя это работает, есть несколько вещей, которые он не сделает для вас.

  1. Связывает ваши фрагменты с тем, что они всегда являются дочерними элементами активности MainActivity, вы можете обойти это с помощью интерфейса, но все равно некрасиво.

  2. Не будет обновлять текущую активность, как только пользователь выберет новый размер текста. Поскольку mainActivity принимает событие меню, вам нужно будет сообщить, какие фрагменты активны, что параметр текста изменился, а затем вызвать notifiyDataSetChanged на адаптере.

  3. Не устанавливает размер текста за пределами пользовательского RecyclerView. Я вижу, у вас есть несколько фрагментов, которые не используют ваш вид ресайклера. Они не примут настройки. Настройка в меню заставит вас думать, что весь текст в приложении должен измениться.

Принятый ответ в этом сообщении кажется хорошим способом настроить текст размер для всего приложения. Некоторые изменения в вашем приложении почти показывают, что вы его видели.

person Gary Bak    schedule 13.10.2016
comment
Я пытаюсь пробиться через ваше объяснение. Я дам вам знать, как это происходит. благодаря. - person The Green Bastard; 14.10.2016
comment
Я абсолютно потерян. Я пытался следовать вашим инструкциям, но понятия не имею, где я должен реализовать код. - person The Green Bastard; 15.10.2016
comment
Я добавил еще некоторые детали. - person Gary Bak; 17.10.2016
comment
Я добавил ваш код и считаю, что все в правильном месте, хотя, когда я запускаю приложение, мое tv_description исчезает из макета. - person The Green Bastard; 18.10.2016
comment
если бы я загрузил свой проект на github, вы бы посмотрели на него для меня и, возможно, указали бы мне на мою ошибку? Я не получаю никаких ошибок в своем логарифме. - person The Green Bastard; 18.10.2016
comment
Конечно, я могу посмотреть. - person Gary Bak; 18.10.2016
comment
Большое спасибо, Гэри Бак. Это мой первый раз, когда я загружаю проект на github, надеюсь, у меня все получилось. - person The Green Bastard; 19.10.2016
comment
проект можно найти по адресу github.com/TheGreenBastard/framework_question. Извините за многострочный ответ, я не использовал для «входа» публикацию вместо того, чтобы дать мне новую строку. еще раз спасибо. - person The Green Bastard; 19.10.2016
comment
Приложение немного сложнее, чем я думал, но с небольшим изменением я смог изменить размер текста, см. мое обновление выше. - person Gary Bak; 19.10.2016
comment
Большое спасибо, Гэри, я борюсь с этим уже почти 2 недели. Я видел этот пост и уверен, что пытался реализовать его хотя бы один раз, но не смог заставить его работать с моими ограниченными знаниями. это уже было в моих закладках, но теперь с помощью вашего ответа выше я смогу заставить его работать в приложении. еще раз, спасибо, что нашли время, чтобы просмотреть мой код. - person The Green Bastard; 20.10.2016
comment
Я забыл упомянуть об этом ранее, но простой способ сообщить всем активным фрагментам об изменении размера текста — использовать Шина событий Вы даже можете использовать закрепленное событие, чтобы последнее выбранное событие оставалось доступным. - person Gary Bak; 20.10.2016