I integrated a Facebook native Ad into a GridView. For now, I display test Ads. It works fine except for the one playing a video.
The MediaView plays a video just fine if the user doesn't interacts with the GridView.
When the GridView is being scrolled, the video is paused and resumed when the Ad reappears on the screen.
After scrolling the grid up and down a few times, the MediaView doesn't show the video anymore and simply displays a grey rectangle.
Out of curiosity, I tried to run Ui Automatic Viewer on my device when the MediaView is grey. I noticed something interesting but I can't really make sense of.
In the View hierarchy, I can see the GridView with a some children FrameLayout (container for the Views given by the adapter). This includes the native ad and the other views.
But when the MediaView is grey, its FrameLayout doesn't appear in the View hierarchy ! But it is rendered just fine on the screen !
I'm very puzzled by what I see.
Also, when I integrated these ads in a RecyclerView, I didn't have this problem (or at least didn't notice it).
Let's talk about the code. I have a reference that points on the Facebook native ad View.
Suggestions welcome :)
Here is the code of the adapter that supplies Views to the GridView :
public class AdapterGridGallery extends BaseAdapter implements AdListener {
private static int POSITION_AD = 4;
private List<QuizzModel> listQuizzes;
int heightViews;
FragmentGallery fragmentGallery;
View facebookAdView;
private NativeAd facebookNativeAd;
private boolean nativeAdSet = false;
public AdapterGridGallery(FragmentGallery fragment, int height) {
heightViews = height;
fragmentGallery = fragment;
facebookNativeAd = new NativeAd(fragment.getContext(), "my_tag");
facebookNativeAd.setAdListener(this);
facebookNativeAd.loadAd();
}
public void updateData(List<QuizzModel> list) {
listQuizzes = list;
notifyDataSetChanged();
}
#Override
public int getCount() {
return listQuizzes != null ? listQuizzes.size() + 1 : 0;
}
#Override
public Object getItem(int i) {
return listQuizzes.get(i);
}
#Override
public long getItemId(int i) {
return listQuizzes.get(i).getId();
}
#Override
public int getItemViewType(int position) {
if (position == POSITION_AD)
return 0;
else
return 1;
}
#Override
public View getView(int position, View convertView, ViewGroup viewGroup) {
View viewQuizz = null;
switch (getItemViewType(position)) {
case 0:
if (facebookAdView == null) {
facebookAdView = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.view_facebook_native, viewGroup, false);
//Settings the height of the view
AbsListView.LayoutParams params = (AbsListView.LayoutParams) facebookAdView.getLayoutParams();
params.height = heightViews;
params.width = AbsListView.LayoutParams.MATCH_PARENT;
facebookAdView.setLayoutParams(params);
}
viewQuizz = facebookAdView;
viewQuizz.setTag(0);
if (facebookNativeAd.isAdLoaded()) {
if (!nativeAdSet) {
Log.d("NativeAdList", "update views resources");
nativeAdSet = true;
ImageView nativeAdIcon = (ImageView) facebookAdView.findViewById(R.id.native_ad_icon);
TextView nativeAdTitle = (TextView) facebookAdView.findViewById(R.id.native_ad_title);
TextView nativeAdBody = (TextView) facebookAdView.findViewById(R.id.native_ad_body);
MediaView nativeAdMedia = (MediaView) facebookAdView.findViewById(R.id.native_ad_media);
TextView nativeAdSocialContext = (TextView) facebookAdView.findViewById(R.id.native_ad_social_context);
Button nativeAdCallToAction = (Button) facebookAdView.findViewById(R.id.native_ad_call_to_action);
nativeAdSocialContext.setText(facebookNativeAd.getAdSocialContext());
nativeAdCallToAction.setText(facebookNativeAd.getAdCallToAction());
nativeAdTitle.setText(facebookNativeAd.getAdTitle());
nativeAdBody.setText(facebookNativeAd.getAdBody());
// Downloading and setting the ad icon.
NativeAd.Image adIcon = facebookNativeAd.getAdIcon();
NativeAd.downloadAndDisplayImage(adIcon, nativeAdIcon);
// Download and setting the cover image.
nativeAdMedia.setNativeAd(facebookNativeAd);
nativeAdMedia.setAutoplay(true);
facebookNativeAd.registerViewForInteraction(facebookAdView);
nativeAdCallToAction.setVisibility(View.VISIBLE);
} else {
Log.d("NativeAdList", "views resources already set");
}
} else {
Log.d("NativeAdList", "nativeAdCallToAction is set invisible");
nativeAdCallToAction.setVisibility(View.INVISIBLE);
}
break;
case 1:
view = new CustomView();
}
return view;
}
#Override
public void onError(Ad ad, AdError adError) {
}
#Override
public void onAdLoaded(Ad ad) {
notifyDataSetChanged();
}
#Override
public void onAdClicked(Ad ad) {
}
}
Here is a screenshot of Ui Automator Viewer.
As you said
when I integrated these ads in a RecyclerView, I didn't have this
problem (or at least didn't notice it).
I interpreted that recycler view work perfectly fine for you. Then instead of trying to redo same thing in gridview simply use LayoutManager to convert recycler view as grid or list.
Related
I used an external library called "Swipe Cards by Diolor" and I attached it to an Array Adapter. Within each card I also need to make a View Pager with bars showing which image the user is currently looking at. The issue I am having is that when I set an OnPageChangeListeneron the View Pager it calls methodonPageSelected and executed all the code within it. This involves a call to createBars (included below). However, everything in createBars is executed including the barHolder.removeAllView except for the li.inflate statements. I also tried using addView but a similar problem occurs. Please advise a method to work around this and if possible the resoan why it's happening. I have included code from the Array Adapter code for the createBars and getView methods. Let me know if some other piece of code would be helpful.
private void createBars(int position, int numItems, LinearLayout barHolder) {
barHolder.removeAllViews();
Log.i("View pager listner", "method called");
for (int i = 0; i < numItems; i++) {
if (i == position) {
li.inflate(R.layout.white_rectangle, barHolder);
} else {
li.inflate(R.layout.transparent_white_rectangle, barHolder);
}
}
}
public View getView(int position, View itemView, ViewGroup parent) {
// all views required for a card
final ProgressBar homeProgressBar;
final TextView homeTimeLeft;
TextView homeTitle;
CardView homeItemHolder;
HomeItem item = getItem(position);
final int numItems = item.getItemImages().length;
if (itemView == null) {
itemView = li.inflate(R.layout.home_item, parent, false);
}
homeProgressBar = itemView.findViewById(R.id.home_progressbar);
homeTimeLeft = itemView.findViewById(R.id.home_time_text);
homeTitle = itemView.findViewById(R.id.home_card_title);
homeViewPager = itemView.findViewById(R.id.home_view_pager);
homeViewPager.setOffscreenPageLimit(6);
timeLeftItem = item.getTimeLeftMiliseconds();
homeTitle.setText(item.getTitle());
HomeImageHolder viewPagerAdapter = new HomeImageHolder(context, item.getItemImages());
homeViewPager.setAdapter(viewPagerAdapter);
final LinearLayout barHolder = itemView.findViewById(R.id.home_bars);
createBars(0, item.getItemImages().length, barHolder);
homeViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
Log.i("view pager listner", "it listned");
createBars(position, numItems, barHolder);
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
countDownTimer = new CountDownTimer(timeLeftItem, milisecondsInHours) {
#Override
public void onTick(long millisUntilFinished) {
homeTimeLeft.setText(HelperMethods.milisecondsToDays(millisUntilFinished) + " Days "
+ HelperMethods.milisecondsToHours(millisUntilFinished) + " Hours");
homeProgressBar.setProgress(updateProgressBar(millisUntilFinished));
}
#Override
public void onFinish() {
homeTimeLeft.setText("0 Days 0 Hours");
homeProgressBar.setProgress(updateProgressBar(0));
}
};
countDownTimer.start();
return itemView;
}
The inflator works when it's called outside the listener but not when it is called inside it. What would be the reasoning being this?
EDIT: I figured out that the class to which the array adapter is added, (Diolor's swipe cards) calls getView 4 times on the future objects in the array. Could this be a potential issue. I know that the reference to bar holder within the listener does not change for a given card. I used Logs and toString methods to confirm that the LinearLayout passed into the listner coincided with the barHolder that corresponds to the current card.
I used an external library called "Swipe Cards by Diolor" and I attached it to an Array Adapter. Within each card I also need to make a View Pager with bars showing which image the user is currently looking at. The issue I am having is that when I set an OnPageChangeListeneron the View Pager it calls methodonPageSelected and executed all the code within it. This involves a call to createBars (included below). However, everything in createBars is executed including the barHolder.removeAllView except for the li.inflate statements. I also tried using addView but a similar problem occurs. Please advise a method to work around this and if possible the resoan why it's happening. I have included code from the Array Adapter code for the createBars and getView methods. Let me know if some other piece of code would be helpful.
private void createBars(int position, int numItems, LinearLayout barHolder) {
barHolder.removeAllViews();
Log.i("View pager listner", "method called");
for (int i = 0; i < numItems; i++) {
if (i == position) {
li.inflate(R.layout.white_rectangle, barHolder);
} else {
li.inflate(R.layout.transparent_white_rectangle, barHolder);
}
}
}
public View getView(int position, View itemView, ViewGroup parent) {
// all views required for a card
final ProgressBar homeProgressBar;
final TextView homeTimeLeft;
TextView homeTitle;
CardView homeItemHolder;
HomeItem item = getItem(position);
final int numItems = item.getItemImages().length;
if (itemView == null) {
itemView = li.inflate(R.layout.home_item, parent, false);
}
homeProgressBar = itemView.findViewById(R.id.home_progressbar);
homeTimeLeft = itemView.findViewById(R.id.home_time_text);
homeTitle = itemView.findViewById(R.id.home_card_title);
homeViewPager = itemView.findViewById(R.id.home_view_pager);
homeViewPager.setOffscreenPageLimit(6);
timeLeftItem = item.getTimeLeftMiliseconds();
homeTitle.setText(item.getTitle());
HomeImageHolder viewPagerAdapter = new HomeImageHolder(context, item.getItemImages());
homeViewPager.setAdapter(viewPagerAdapter);
final LinearLayout barHolder = itemView.findViewById(R.id.home_bars);
createBars(0, item.getItemImages().length, barHolder);
homeViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
Log.i("view pager listner", "it listned");
createBars(position, numItems, barHolder);
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
countDownTimer = new CountDownTimer(timeLeftItem, milisecondsInHours) {
#Override
public void onTick(long millisUntilFinished) {
homeTimeLeft.setText(HelperMethods.milisecondsToDays(millisUntilFinished) + " Days "
+ HelperMethods.milisecondsToHours(millisUntilFinished) + " Hours");
homeProgressBar.setProgress(updateProgressBar(millisUntilFinished));
}
#Override
public void onFinish() {
homeTimeLeft.setText("0 Days 0 Hours");
homeProgressBar.setProgress(updateProgressBar(0));
}
};
countDownTimer.start();
return itemView;
}
The inflator works when it's called outside the listener but not when it is called inside it. What would be the reasoning being this?
EDIT: I figured out that the class to which the array adapter is added, (Diolor's swipe cards) calls getView 4 times on the future objects in the array. Could this be a potential issue. I know that the reference to bar holder within the listener does not change for a given card. I used Logs and toString methods to confirm that the LinearLayout passed into the listner coincided with the barHolder that corresponds to the current card.
I have a recyclerview adapter that is based on inflating two different card layouts. This adapater is dynamically updated with new cards and therefore each of the cards in the adapter needs to be updated as well. For each of the cards, there are a progressbar showing random generated data.
However, the problem Im facing is when I remove one of the cards in my list, the reference for the deleted card is not removed (the onCreateViewHolder is not called and therefore does not update the views), instead the cards left are just writing over the layout of the "deleted" card. The text on the card is correct and it removes the correct item from the list, but the progress bar is still having the old reference for the old card, which makes it adding values that corresponds to the deleted card.
To illustrate the problem, I'm adding random data to each of the cards in the progressbar depending on the movement name. So regardless of the card, the movement card named "Open Hand" should always add random data between 0-20, "Close hand" 20-60" and "Pronation" 60-100".
Here is everything working as supposed after adding three cards:
After inserted three cards
But when I delete the two first cards "Open hand" and "Close hand", the "Pronation" card left is showing the data in progress bar that actually corresponds to the "Open hand" data range. So why isn't the referencing correct?
I've tried calling both onDataSetChange(); and notifyItemRemoved(pos);
After deleted two cards
My adapter code:
public class ParameterAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
List<Movement> movements;
public ParameterAdapter() {
this.movements=movementList;
}
class AddCard extends RecyclerView.ViewHolder {
public AddCard(View inflate) {
super(inflate);
}
}
class Card extends RecyclerView.ViewHolder {
TextView movement;
TextView channel;
TextView remove;
ProgressBar strength;
TextView graph;
LinearLayout expandedView;
LineChart lineChart;
Movement mov;
public Card(View itemView, Movement m) {
super(itemView);
movement = (TextView) itemView.findViewById(R.id.movementText);
channel = (TextView) itemView.findViewById(R.id.channelNameText);
remove = (TextView) itemView.findViewById(R.id.removeCard);
strength = (ProgressBar) itemView.findViewById(R.id.progressBarStrength);
graph = (TextView) itemView.findViewById(R.id.graphTextButton);
expandedView = (LinearLayout) itemView.findViewById(R.id.detailsNr2);
lineChart = (LineChart) itemView.findViewById(R.id.linechartCard);
mov=m;
channel.setText(m.getChannel());
//Setup real time graph
setupLineChart(mov, lineChart, mov.getId());
// Start adding random data to the graph
startAddingRandomData();
}
public void startAddingRandomData() {
new Thread(
new Runnable() {
public void run() {
while (true) {
int generatedData;
// Depending on what type of movement, add slightly different generated random data
// (to be sure that the views are correctly updated when removed for instance)
if(mov.getSettingsType().equals(SettingsDbHelper.MOVEMENTS_STRING[0])){
// Add random generated data between the span 0-20
generatedData=generateRandomData(0,20);
} else if (mov.getSettingsType().equals(SettingsDbHelper.MOVEMENTS_STRING[1])) {
// Add random generated data between the span 20-60
generatedData=generateRandomData(20, 60);
} else {
// Add random generated data between the span 60-100
generatedData=generateRandomData(60, 100);
}
//Set the progress bar
strength.setProgress(generatedData);
// Add the random generated data to the graph
addEntry(mov, lineChart, generatedData);
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
public int generateRandomData(int n1, int n2){
Random r = new Random();
return r.nextInt(n2 - n1) + n1;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View vSetting=null;
View vCard=null;
// If its the first position, then inflate the "add movement" card.
if(viewType==0) {
vSetting = LayoutInflater.from(parent.getContext()).inflate(R.layout.fragment_parameter_cardview, parent, false);
return new AddCard(vSetting);
}else if(viewType>0) {
// Otherwise, if it's not the first position, then inflate a "movement card" and create the corresponding movement item
vCard = LayoutInflater.from(parent.getContext()).inflate(R.layout.cardview_movement, parent, false);
Movement m = movementList.get(viewType - 1);
return new Card(vCard, m);
}else {
// For some reason, this occurs
return null;
}
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder,final int position) {
// "Add movement" card
if(position==0){
((AddCard)holder).itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(getActivity(), AddMovement.class);
startActivityForResult(intent, ADD_MOVEMENT);
}
});
// "Movement" item card
} else if(position>0) {
final boolean isExpanded = position == mExpandedPosition;
((Card) holder).expandedView.setVisibility(isExpanded ? View.VISIBLE : View.GONE);
((Card) holder).graph.setActivated(isExpanded);
((Card) holder).graph.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mExpandedPosition = isExpanded ? -1 : position;
notifyDataSetChanged();
}
});
// Get the type of movement
Movement m = movementList.get(position - 1);
// This lets the real-time graph view be created before actual adding any data.
m.setChartCreated(1);
//Update the textviews inside the card
((Card)holder).movement.setText(m.getMovement());
((Card)holder).channel.setText(m.getChannel());
((Card)holder).remove.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Movement m = movementList.get(position - 1);
//Remove the item from the list
remove(m);
// Get ID and settings type in order to update the entry
String id=m.getId();
String settingsType = m.getSettingsType();
//Update the entry
settingsdb.updateSetting(settingsType,id,"false");
}
});
}
}
// Remove item from the list
public void remove(Movement data) {
int position = movementList.indexOf(data);
movementList.remove(data);
notifyDataSetChanged();
// (+ 1 one to compensate for the first card)
notifyItemRemoved(position + 1);
}
#Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
#Override
public int getItemViewType(int position) {
//Return the position
return position;
}
#Override
public int getItemCount() {
// (+1 to compensate for the first card)
return movementList.size()+1;
}
}
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?
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:
Add a setText/getText size to the adapter and the activity can set this when needed.
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.
Add a getDynamicTextSize in your MainActivity
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.
Ties your fragments to always being a child of the MainActivity activity, you can get around this with an interface, but still not pretty.
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.
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.
I have problems with RecyclerView when I try to loop adding more child views to the parent view. When I scroll, it appears blank for a second. Is from Data binding or the view rendering?
Here is my code:
public class TournamentFixtureAdapter extends LoadMoreRecyclerViewAdapter<FixtureGroup> {
private OnFixtureClickListener onFixtureClickListener = null;
public TournamentFixtureAdapter(List<FixtureGroup> data) {
super(data);
}
#Override
protected RecyclerView.ViewHolder onCreateContentItemViewHolder(ViewGroup parent, int contentViewType) {
return new TournamentFixtureHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_tournament_fixture, parent, false));
}
#Override
protected void onBindContentItemViewHolder(RecyclerView.ViewHolder holder, int position) {
super.onBindContentItemViewHolder(holder, position);
FixtureGroup fixtureGroup = data.get(position);
((TournamentFixtureHolder) holder).onFixtureClickListener = onFixtureClickListener;
((TournamentFixtureHolder) holder).parentPos = position;
((TournamentFixtureHolder) holder).binding.setFixtureGroup(fixtureGroup);
((TournamentFixtureHolder) holder).addFixtures(fixtureGroup.getFixtures());
}
public void setOnFixtureClickListener(OnFixtureClickListener onFixtureClickListener) {
this.onFixtureClickListener = onFixtureClickListener;
}
static class TournamentFixtureHolder extends FixtureHolder {
ListItemTournamentFixtureBinding binding = null;
public TournamentFixtureHolder(View itemView) {
super(itemView);
binding = DataBindingUtil.bind(itemView);
}
}
}
public class FixtureHolder extends BaseAdapter.BaseHolder {
LinearLayout layoutMain = null;
OnFixtureClickListener onFixtureClickListener = null;
int parentPos;
public FixtureHolder(View itemView) {
super(itemView);
layoutMain = (LinearLayout) itemView.findViewById(R.id.layout_main);
setIsRecyclable(layoutMain.getChildCount() > 0);
}
public void addFixtures(final ArrayList<Fixture> fixtures) {
for (final Fixture fixture : fixtures) {
LinearLayout parent = (LinearLayout) LayoutInflater.from(itemView.getContext()).inflate(R.layout.view_fixture, null);
Utils.getDefaultClubLogo((NetworkImageViewPlus) parent.findViewById(R.id.netview_home_img)).setImageUrl(fixture.getHome().getImg(), AppController.getInstance().getImageLoader());
Utils.getDefaultClubLogo((NetworkImageViewPlus) parent.findViewById(R.id.netview_away_img)).setImageUrl(fixture.getAway().getImg(), AppController.getInstance().getImageLoader());
ViewFixtureBinding binding = DataBindingUtil.bind(parent);
layoutMain.addView(parent);
binding.setFixture(fixture);
parent.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onFixtureClickListener.onFixtureClick(parentPos, findFixturePosById(fixtures, fixture.getId()));
}
});
}
}
private int findFixturePosById(ArrayList<Fixture> fixtures, int id) {
for (int i = 0; i < fixtures.size(); i++) {
if (fixtures.get(i).getId() == id) {
return i;
}
}
return 0;
}
}
If the problem was more on the data side (adapter), then it would probably be showing up on the normal layout, not just during scrolling. For instance, if you were loading images from a slow server, the initial display would be slow. Since it's only happening when you scroll, that points more to a problem with the layout manager.
For every new view, you have to get it from the adapter, and add it to the layout. If you allow maximum dx in horizontal/vertical scrolling, and have recycled views outside of the screen display cached, it's likely that things will appear blank prior the layout manager getting the new views from the adapter and laying them out.
So there are two factors - horizontal and/or vertical dx is too large, too soon, and the number of recycled (or scrapped) views is too small. So the solution is to either slow down scrolling, or to increase the number of views you are adding off-screen.