0

Im trying to implement a dynamic text size option within my app. For some reason the recycler is only randomly changing text size within my cardviews instead of setting all the text to the desired size. As I scroll the list, the top cardview text will change correctly but the next 3-4 will stay default and randomly down the list another cardview text will display correctly. when i scroll back up the list, the cardview that displays correctly will change at random.

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

My Adapter....

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

Holder....

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

Do I need to add something to my adapter or viewholder to update all the text properly?

1 Answers1

0

I think I get it, but I don't see where you are setting the text size at all, you said it changes in some cards randomly.

As I see it, what needs to be done is to set the size in the Holder's bind method. This gets executed every time the card needs to be redrawn. You can read the shared preferences inside the bind(), but that is terribly inefficient since the holder's bind method will be called many times over when scrolling. You wan to avoid any excess work inside the Holders bind()

Add a dynamicTextSize member variable to the adapter and set the value with either:

  1. Add a setText/getText size to the adapter and the activity can set this when needed.
  2. Retrieve the text size inside the adapter's constructor and then override the notifyDataSetChanged() method and pull the value again each time that is called. Then call super.notifyDataSetChanged()

Example:

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

What I also don't see is the dynamicTextSize value being passed into the holder. Since the holder has a reference to the adapter, you can add a getTextSize() method to the adapter, then the holder can call into the adapter to get it.

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

Finally, in the setTextSize() method you'll need to call the adapter.notifyDataSetChanged() to update the adapter.

Update 10/17

I've attempted to add some detail to by previous post.

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

In your adapter, add a method to set and get the text size. The set will be called by the main activity, when the text size changes, and the get is called by the holder each time it needs to set the size of the 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;
    } 
    ...
}

In your holder:

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

Update 10/19

I was able to get it to work with just a small change.

  1. Add a getDynamicTextSize in your MainActivity
  2. Add a call to the get from within the MyPageAdapter constructor.

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

While this does work, there is are few things it will not do for you.

  1. Ties your fragments to always being a child of the MainActivity activity, you can get around this with an interface, but still not pretty.

  2. Will not update the current activity as soon as the user chooses the new text size. Since the mainActivity takes the menu event, you will need to inform whatever Fragment(s) is/are active, that the text setting has changed and then call notifiyDataSetChanged on the adapter.

  3. Does not set the size of the text outside of the custom RecyclerView. I see you have a few fragments that do not use you recycler view. These will not take the setting. The setting in the menu would make you think all the text in the app should change.

The accepted reply in this post seems to be a good way to adjust the text size for the entire app. Some changes in your app almost show that you've seen it.

Community
  • 1
  • 1
Gary Bak
  • 4,746
  • 4
  • 22
  • 39
  • Im trying to fight my way through your explanation. Ill let you know how it goes. thanks. – The Green Bastard Oct 14 '16 at 17:13
  • I'm absolutely lost. I tried to follow your instructions but I have no idea where im supposed to implement the code. – The Green Bastard Oct 15 '16 at 20:59
  • I've added some more detail. – Gary Bak Oct 17 '16 at 11:38
  • I have added your code and believe everything is in the right spot, although when i run the app it makes my tv_description disappear from the layout. – The Green Bastard Oct 18 '16 at 13:39
  • if I were to upload my project to github, would you take a look at it for me and possibly direct me to my error? Im not getting any errors in my logcat. – The Green Bastard Oct 18 '16 at 13:40
  • Sure, I can take a look. – Gary Bak Oct 18 '16 at 16:56
  • thank you so much Gary Bak. This is my first time uploading a project to github, I hope i got everything. – The Green Bastard Oct 19 '16 at 16:04
  • the project can be found at https://github.com/TheGreenBastard/framework_question. Sorry for the multi line reply's, not used to 'enter' posting instead of giving me a new line. thanks again. – The Green Bastard Oct 19 '16 at 16:06
  • App is quite a bit more complicated than I had thought, but with a small change I was able to get the text to change sizes, see my update above. – Gary Bak Oct 19 '16 at 19:11
  • Thank you so much Gary, i have been fighting with this for almost 2 weeks now. I had seen that post and im sure i tried to implement it at least once, but I couldnt get it to work with my limited knowledge. it was in my bookmarks already but now with the help from your reply above I should be able to get it working app wide. again, thank you for taking the time to review my code. – The Green Bastard Oct 20 '16 at 05:12
  • I forgot to mention it earlier, but an easy way to inform all active fragments of a text size change would be to use an [Event Bus](https://github.com/greenrobot/EventBus) You can even use a sticky event to keep the last currently selected available. – Gary Bak Oct 20 '16 at 11:02