I am using viewpager with Pager adapter and passing an arraylist in the adapter. The arraylist has size "0" in the start but once it is filled, I am calling viewpager.notifydatasetchanged().After calling notifydatasetchanged the method CharSequence getPageTitle(int position) is not called and titles are not updated dynamically.
My adapter code:
public class MyViewPagerAdapter extends PagerAdapter {
private ArrayList<String> arrayList;
private Activity activity;
public ViewPagerAdapter(Activity activity, ArrayList<String> arrayList) {
this.activity = activity;
this.arrayList = arrayList;
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
#Override
public int getCount() {
return arrayList.size();
}
#Override
public boolean isViewFromObject(#NonNull View view, Object o) {
return o == view;
}
#NonNull
#Override
public Object instantiateItem(#NonNull ViewGroup container, int position) {
// Inflate a new layout from our resources
View view = activity.getLayoutInflater().inflate(R.layout.pager_item,
container, false);
// Add the newly created View to the ViewPager
container.addView(view);
// Retrieve a TextView from the inflated View, and update it's text
TextView tvWeatherDescription = view.findViewById(R.id.tv);
// Return the View
return view;
}
#Override
public CharSequence getPageTitle(int position) {
return arrayList.get(position);
}
#Override
public void destroyItem(#NonNull ViewGroup container, int position, #NonNull Object object) {
container.removeView((View) object);
}
}
My Activity code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ArrayList<String> arrayList = new ArrayList<String>
ViewPager viewpager = findviewbyId(R.id.viewpager);
MyViewPagerAdapter adapter = new MyViewPagerAdapter(MainActivity.this, arraylist);
viewpager.setAdapter(adapter);
SlidingTabLayout slidingTabLayout = findViewById(R.id.sliding_tabs);
slidingTabLayout.setViewPager(viewpager);
}
Once the size of arraylist is changed I am calling it like this:
arraylist.add("Item1")
adapter.notifydatasetchanged();
but the title value is not changing.Is there any way that method CharSequence getPageTitle(int position) is called after notifydatasetchanged?
Related
Good morning,
I have a Fragment which its layout has a ViewPager, I provide a custom PageAdapter to show two child layouts. One layout is to fill with personal data and another layout is to fill with Address data by the user. On my fragment I want to retrieve both layouts data and fill a object Pessoa(Person) with an attribute Endereco (Address). So far my ViewPager is working and both layout are displayed, however when I try to get the fields on both layouts, either on onCreateView or onResume fragment's method, using :
viewpager.getChildAt(0).findViewById(R.id.txt1)
I got an NullPointerException, but if I add an OnPageChangeListener this works, I not sure if it's the best approach. Is There a best place to retrieve a reference to the viewpager child's layout?
Ps. I don't want to use two other Fragments in order to display each of the layouts.
PageAdapter
public class ViewPagerCadastroPessoaAdapter extends PagerAdapter {
private Context context;
private int[] views = {R.layout.layout_cadastro_dados_pessoais,R.layout.layout_cadastro_endereco };
public ViewPagerCadastroPessoaAdapter(Context context) {
this.context = context;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
LayoutInflater inflater = LayoutInflater.from(this.context);
View layout = inflater.inflate(views[position], container, false);
container.addView(layout, position);
return layout;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
#Override
public int getCount() {
return 2;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position){
case 0:
return "Dados Pessoais";
case 1:
return "Endereço";
}
return super.getPageTitle(position);
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}}
ViewPager's holder Fragment
public class CadastroPessoaFragment extends Fragment {
private ViewPager viewPagerCadastroPessoa;
private TabLayout tabLayoutCadastroPessoa;
public CadastroPessoaFragment() {
}
public static CadastroPessoaFragment newInstance() {
return new CadastroPessoaFragment();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_cadastro_pessoa, container, false);
tabLayoutCadastroPessoa = root.findViewById(R.id.tabLayoutCadastroPessoa);
viewPagerCadastroPessoa = root.findViewById(R.id.viewPagerCadastroPessoa);
viewPagerCadastroPessoa.setOffscreenPageLimit(2);
viewPagerCadastroPessoa.setAdapter(new ViewPagerCadastroPessoaAdapter(getContext()));
tabLayoutCadastroPessoa.setupWithViewPager(viewPagerCadastroPessoa);
int cor = ContextCompat.getColor(getContext(), android.R.color.white);
tabLayoutCadastroPessoa.setTabTextColors(cor, cor);
//get a null pointer
viewPagerCadastroPessoa.getChildAt(0).findViewById(R.id.txt1);
viewPagerCadastroPessoa.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
//works fine
viewPagerCadastroPessoa.getChildAt(0).findViewById(R.id.txt1);
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
return root;
}
#Override
public void onResume() {
super.onResume();
//get a null pointer
viewPagerCadastroPessoa.getChildAt(0).findViewById(R.id.txt1);
}
}
Thank you all in advance
UPDATE
According with
Anton Malyshev answer
The way Viewpager creates its pages is kind of "unsynchronized", so I used the following approach to solve my problem:
On my custom adapter I definied an interface with a single method onViewPagerReady(), as my Viewpager will always have only two pages, inside instantiateItem I check when position is 1 (once position starts with 0), if position == 1 I call the method onViewPagerReady that my fragment viewpager's holder implements, so inside this method I retrieve the layout of viewpager's children
public class ViewPagerCadastroPessoaAdapter extends PagerAdapter {
public interface ViewPagerObserver{
void onViewPagerReady();
}
private Context context;
private int[] views = {R.layout.layout_cadastro_dados_pessoais,R.layout.layout_cadastro_endereco };
private ViewPagerObserver observer;
public ViewPagerCadastroPessoaAdapter(Context context, ViewPagerObserver observer) {
this.context = context;
this.observer = observer;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
LayoutInflater inflater = LayoutInflater.from(this.context);
View layout = inflater.inflate(views[position], container, false);
container.addView(layout, position);
if(position == 1){
observer.onViewPagerReady();
}
return layout;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
#Override
public int getCount() {
return 2;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position){
case 0:
return "Dados Pessoais";
case 1:
return "Endereço";
}
return super.getPageTitle(position);
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
}
Fragment Viewpager's Holder
#Override
public void onViewPagerReady() {
View rootCadastroDadosPessoais = viewPagerCadastroPessoa.getChildAt(0);
View rootCadastroEnderecos =viewPagerCadastroPessoa.getChildAt(1);
}
Thank you all.
Just wait until viewPagerCadastroPessoa.getChildCount() will be greater than 0. The pages in ViewPager are not created yet in onResume (they are created asynchronously).
My pageView should show the same listview but each time with different information.
The information is selected through the position parameter sent to the function instantiateItem:
public Object instantiateItem(ViewGroup collection, int position)
The problem that position is not correct as I get never position=1 . It's always 0 or 2.
class MyPagerAdapter extends PagerAdapter
{
ListView myListView;
#Override
public Object instantiateItem(ViewGroup collection, int position) {
Log.v("position",position+"");
LayoutInflater inflater = LayoutInflater.from(MyAndAllWordsActivity.this);
ViewGroup myView = (ViewGroup) inflater.inflate(R.layout.my_view_pager_list_view, collection, false);
myListView =(ListView)myView.findViewById(R.id.my_list_view);
MyCustomAdapter listViewAdapter = setDataForListView(position);
myListView.setAdapter(listViewAdapter);
collection.addView(myView);
return myView;
}
#Override
public void destroyItem(ViewGroup collection, int position, Object view) {
collection.removeView((View) view);
}
#Override
public int getCount() {
return 3;
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
#Override
public CharSequence getPageTitle(int position) {
String tabTitel =null;
switch (position){
case 0 :
tabTitel= "Namen";
break;
case 1 :
tabTitel= "Adjektive";
break;
case 2 :
tabTitel= "Verben";
break;
}
return tabTitel;
}
}
mainActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
TabLayout mTabLayout;
SearchView mSearchView;
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_and_all_words);
ViewPager mPager=(ViewPager) findViewById(R.id.pager);
mPager.setAdapter(new MyPagerAdapter());
//mPager.setCurrentItem(mPager.getCurrentItem());
mTabLayout = (TabLayout) findViewById(R.id.tab_layout);
mTabLayout.setupWithViewPager(mPager);
I have a regular ViewPager with an adapter:
public class MyDialogFragment extends DialogFragment {
private ViewPager viewPager;
private MyViewPagerAdapter myViewPagerAdapter;
private City city;
public static MyDialogFragment newInstance() {
MyDialogFragment fragment = new MyDialogFragment();
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_layout, container, false);
viewPager = (ViewPager) v.findViewById(R.id.viewPager);
city = Parcels.unwrap(getArguments().getParcelable("city"));
myViewPagerAdapter = new MyViewPagerAdapter(getContext());
viewPager.setAdapter(myViewPagerAdapter);
viewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
// Page changed
}
});
return v;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public class MyViewPagerAdapter extends PagerAdapter {
private Context context;
private LayoutInflater layoutInflater;
public MyViewPagerAdapter(Context context) {
this.context = context;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
layoutInflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = layoutInflater.inflate(R.layout.city_layout, container, false);
ImageView imageView = (ImageView) view.findViewById(R.id.cityImage);
Glide.with(context)
.load(city.getImage())
.into(imageView);
}
container.addView(view);
return view;
}
#Override
public int getCount() {
return city.size();
}
#Override
public boolean isViewFromObject(View view, Object obj) {
return view == ((View) obj);
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
}
}
As you can see, I have a page change listener set on my ViewPager. But I need to be able to notify the adapter when the page has changed so that I can modify the adapter's ImageView. How can I do this?
Add a method to your adapter class
public class MyViewPagerAdapter extends PagerAdapter {
...
public void pageChanged(int position) {
// Do something
}
...
}
After that in your OnPageChangeListener use that method
#Override
public void onPageSelected(int position) {
myViewPagerAdapter.pageChanged(position);
}
One approach is to create a data structure in your adapter to map the pager view to its position. A SparseArray is most efficient:
private SparseArray<View> pageMap = new SparseArray<>();
Then in the adapter's instantiateItem() method, add the view to the SparseArray:
public Object instantiateItem(ViewGroup container, int position) {
...
pageMap.put(position, view);
...
}
Now in your OnPageChangeListener you can do the following:
#Override
public void onPageSelected(int position) {
View view = adapter.getView(pos);
if (view != null) {
ImageView iv = (ImageView) view.findViewById(R.id.your_image_view);
// You now have the image view
}
}
Make sure you remove views from the SparseArray in the adapter's destroyItem() method:
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
pageMap.remove(position);
...
}
You can use the constructor with imagelist to pass and that automatically called on next page..In your code will be modified like :::
ArrayList imageList=new ArrayList<>();
imageList.add("ImagePath here");
myViewPagerAdapter = new MyViewPagerAdapter(getContext(),imageList);
viewPager.setAdapter(myViewPagerAdapter);
Then your adapter will be like ::
public class MyViewPagerAdapter extends PagerAdapter {
private Context context;
private ArrayList<String> imageList
private LayoutInflater layoutInflater;
public MyViewPagerAdapter(Context context,ArrayList<String> imageList) {
this.context = context;
this.imageList = imageList;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
layoutInflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = layoutInflater.inflate(R.layout.city_layout, container, false);
ImageView imageView = (ImageView) view.findViewById(R.id.cityImage);
Glide.with(context)
.load(imageList.get(position)) // This will be changes like
.into(imageView);
}
container.addView(view);
return view;
}
#Override
public int getCount() {
return city.size();
}
#Override
public boolean isViewFromObject(View view, Object obj) {
return view == ((View) obj);
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
}
That done ..
After this, there are some suggestion that
- please use arraylist while using the viewpager ..
Now you just taking the parceble object from bundle..
you can do the same for the arraylist,
just receive the arraylist from the same bundle by passing the whole arraylist at once.
so you dont need to find the page change event..viewpager will automatically handle that..
Here's How to send & receiving the parceable arraylist
// while sending the list
Bundle bundle = new Bundle();
bundle.putParcelableArrayList("citylist", new ArrayList<City>());
// while receiving the list
ArrayList<City> citylist = getIntent().getParcelableArrayListExtra("citylist");
After this just get the all image and add in the imagelist array
for (int i = 0; i < citylist.size(); i++) {
imageList.add(citylist.get(i).getImage());
}
And pass this imageList in
myViewPagerAdapter = new MyViewPagerAdapter(getContext(),imageList);
viewPager.setAdapter(myViewPagerAdapter);
Tell me if needed more assitance.
i implemented a viewpager in my activity that on scroll, loads a set of data to an adapter and display them in a list view. everything is working fine, but i cant seem to find out how to make it more efficient because when scrolling, the view freezes but for example in the GMAIL app when scrolling between Emails the scrolling is so smooth.
Below is the code i am using:
Activity:
in oncreate
pageradapter adapter2 = new pageradapter(this, ArrayOfItems); //ArrayOfItems is an Array containing the data that will be displayed
ViewPager myPager = (ViewPager) findViewById(R.id.mypanelpager);
myPager.setAdapter(adapter2);
pagechangelistener pageListener = new pagechangelistener();
myPager.setOnPageChangeListener(pageListener);
pageradapter:
public pageradapter(Activity act, ArrayList <List<Item>>Arrayitems) {
this.Arrayitems = Arrayitems;
activity = act;
}
public int getCount() {
return Arrayitems.size();
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
List<Item> item = Arrayitems.get(position);
ListView view = new ListView(activity);
taskdetailsarrayadaptertest adapter = new taskdetailsarrayadaptertest(activity, item);
view.setAdapter(adapter);
view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
((ViewPager) container).addView(view, 0);
return view;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
((ViewPager) container).removeView((View) object);
}
#Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == ((View) arg1);
}
#Override
public Parcelable saveState() {
return null;
}
pagechangelistener:
#Override
public void onPageSelected(int position)
{
currentPage = position;
int positionTemp = position + 1;
}
public final int getCurrentPage() {
return currentPage;
}
First you need to use holders like this.
in your ViewPager:
class Holder{
ListView listView;
Adapter adapter;
}
private ArrayList<Holder> mHolders;
//init holders
#Override
public Object instantiateItem(ViewGroup collection, int position) {
Holder holder = mHolders.get(position);
holder.listView.setAdapter(holder.adapter);
collection.addView(holder.listView);
return holder.listView;
}
Second try async loading data in listview
set myPager.setOffscreenPageLimit(1);
I have been working on an app to take the blog feed and parse and display it in the app using the Recycler and Card View. I got to the point of adding sliding tabs to display articles in each of the categories in the site in separate tabs. I parse the feed using the category URL and am able to display it using the same Recycler view adapter.
Here comes the problem, as I swipe through the tabs quickly, the content doesn't load in some cases. In some cases, I get articles from one category displayed in another category's tab.
Below is the code for my Tabs fragment:
public class TabsFragment extends Fragment {
ViewPager mViewPager;
ViewPagerAdapter mAdapter;
SlidingTabLayout mSlidingTabLayout;
CharSequence Titles[] = {"Home", "Events", "Category", "Bookmarks", "News"};
int NoOfTabs = 5;
private ProgressBar mProgressBar;
private RecyclerView mRecyclerView;
private MyRecyclerViewAdapter myRecyclerViewAdapter;
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.activity_tabs, container, false);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
mAdapter = new ViewPagerAdapter(Titles, NoOfTabs);
mProgressBar = (ProgressBar) view.findViewById(R.id.loading_spinner);
mViewPager = (ViewPager) view.findViewById(R.id.pager);
mViewPager.setAdapter(mAdapter);
mSlidingTabLayout = (SlidingTabLayout) view.findViewById(R.id.tabs);
mSlidingTabLayout.setCustomTabColorizer(new SlidingTabLayout.TabColorizer() {
#Override
public int getIndicatorColor(int position) {
return getResources().getColor(R.color.secondaryBackgroundColor);
}
#Override
public int getDividerColor(int position) {
return getResources().getColor(R.color.secondaryBackgroundColor);
}
});
mSlidingTabLayout.setViewPager(mViewPager);
}
public class ViewPagerAdapter extends PagerAdapter {
CharSequence mTitles[];
int mNoOfTabs;
public ViewPagerAdapter(CharSequence[] titles, int noOfTabs) {
mTitles = titles;
mNoOfTabs = noOfTabs;
}
public CharSequence getPageTitle(int position) {
return mTitles[position];
}
#Override
public int getCount() {
return mNoOfTabs;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
View view = getActivity().getLayoutInflater().inflate(R.layout.pager_item_articles,
container, false);
container.addView(view);
ProcessArticles processArticles;
processArticles = new ProcessArticles(null, mTitles[position]);
processArticles.execute();
mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity().getApplicationContext()));
myRecyclerViewAdapter = new MyRecyclerViewAdapter(new ArrayList<Article>(),
getActivity().getApplicationContext());
mRecyclerView.setAdapter(myRecyclerViewAdapter);
return view;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
#Override
public boolean isViewFromObject(View view, Object object) {
return object == view;
}
}
public class ProcessArticles extends GetXmlData {
public ProcessArticles(String searchCriteria, String category) {
super(searchCriteria, category);
}
#Override
public void execute() {
super.execute();
ProcessData processData = new ProcessData();
processData.execute();
}
public class ProcessData extends DownloadXmlData {
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
ParseArticles parseArticles = new ParseArticles(getData());
boolean operationStatus = parseArticles.process();
if (operationStatus) {
ArrayList<Article> allArticles = parseArticles.getArticles();
myRecyclerViewAdapter.loadNewData(allArticles);
} else {
Toast.makeText(getActivity().getApplicationContext(), "Error establishing correction.", Toast.LENGTH_SHORT).show();
Log.d("MainActivity", "Error establishing correction.");
}
}
}
}
}
The code for the activity displaying the tabs is:
public class TabsActivity extends BaseActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_tabs);
activateToolbarWithHomeEnabled();
if (savedInstanceState == null) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
TabsFragment fragment = new TabsFragment();
transaction.replace(R.id.tab_content_frame, fragment);
transaction.commit();
}
}
}
How do I separate the content according to category in the tabs? I have tried to reduce the amount of code, so, I have used the same Recycler adapter. Is there any solution to this problem? Or should I change the method of implementation? I am looking to implement something like the Play Newsstand app.