I have a tablayout, from android design support library:
compile 'com.android.support:design:23.0.1'
With this, I want to populate my tabs. But I'm failing to do that. I can create the tabs, but they fail to inflate their respective content:
Where it should have entries from LinearListView, an object similar to a ListView imported from this framework:
compile 'com.github.frankiesardo:linearlistview:1.0.1#aar'
I tried a great number of examples, but I failed to populate each tab. Any suggestions?
Code:
JAVA:
From main fragment:
OverviewTabLayoutPagerAdapter adapter = new OverviewTabLayoutPagerAdapter(getActivity().getSupportFragmentManager(), productDataContent, getContext());
ViewPager viewPager = (ViewPager) view.findViewById(R.id.viewpager);
viewPager.setAdapter(adapter);
TabLayout tabLayout = (TabLayout) view.findViewById(R.id.tablayout);
tabLayout.setupWithViewPager(viewPager);
OverviewTabLayoutPagerAdapter:
public class OverviewTabLayoutPagerAdapter extends FragmentPagerAdapter {
final int PAGE_COUNT = 3;
private String tabTitles[] = new String[] { "REVIEWS", "VIDEOS", "DEALS" };
private SearchContent productDataContent;
private Context context;
public OverviewTabLayoutPagerAdapter(FragmentManager fm, SearchContent productDataContent, Context context) {
super(fm);
this.productDataContent = productDataContent;
this.context = context;
}
#Override
public int getCount() {
return PAGE_COUNT;
}
#Override
public Fragment getItem(int position) {
Log.i("TAB_POSITION", String.valueOf(position));
if (position == 0) {
return OverviewTab1Fragment.newInstance(position, productDataContent);
} else if (position == 1) {
return OverviewTab2Fragment.newInstance(position, productDataContent);
} else if (position == 2) {
return OverviewTab3Fragment.newInstance(position, productDataContent);
}
return OverviewTab1Fragment.newInstance(position, productDataContent);
}
#Override
public CharSequence getPageTitle(int position) {
// Generate title based on item position
return tabTitles[position];
}
OverviewTab*Fragment: (the * means the same code structure applies for every fragment):
public class OverviewTab*Fragment extends Fragment {
public static final String ARG_PAGE = "ARG_PAGE";
public static final String PRODUCT_DATA_CONTENT = "PRODUCT_DATA_CONTENT";
private int mPage;
private SearchContent productDataContent;
public static OverviewTab*Fragment newInstance(int page, SearchContent productDataContent) {
OverviewTab*Fragment fragment = new OverviewTab*Fragment();
Bundle args = new Bundle();
args.putInt(ARG_PAGE, page);
args.putSerializable(PRODUCT_DATA_CONTENT, productDataContent);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPage = getArguments().getInt(ARG_PAGE);
productDataContent = (SearchContent) getArguments().getSerializable(PRODUCT_DATA_CONTENT);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.overview_tab_fragment, container, false);
LinearListView tabContentListView = (LinearListView) view.findViewById(R.id.product_content_linear_list_view);
populateOverviewTab*LinearLayout(tabContentListView, productDataContent);
return view;
}
private void populateOverviewTab*LinearLayout(LinearListView tabContentListView, SearchContent productDataContent) {
ArrayList<> productData = productDataContent.getContent();
OverviewTab*ArrayAdapter overviewTab*ArrayAdapter = new OverviewVideosArrayAdapter(
getContext(),
tabContentListView,
productData,
getActivity()
);
tabContentListView.setAdapter(overviewTab*ArrayAdapter);
...
XML:
From main fragment:
...
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/go_to_store_button"
android:orientation="vertical">
<android.support.design.widget.TabLayout
android:id="#+id/tablayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabGravity="fill" />
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
</LinearLayout>
...
overview_tab_fragment.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.linearlistview.LinearListView
android:id="#+id/product_content_linear_list_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:showDividers="end"
android:dividerPadding="5dp"
app:dividerThickness="2dp">
</com.linearlistview.LinearListView>
</RelativeLayout>
You can change:
#Override
public Fragment getItem(int position) {
Log.i("TAB_POSITION", String.valueOf(position));
if (position == 0) {
return OverviewTab1Fragment.newInstance(position, productDataContent);
} else if (position == 1) {
return OverviewTab2Fragment.newInstance(position, productDataContent);
} else if (position == 2) {
return OverviewTab3Fragment.newInstance(position, productDataContent);
}
return OverviewTab1Fragment.newInstance(position, productDataContent);
}
for this:
#Override
public Fragment getItem(int position) {
Log.i("TAB_POSITION", String.valueOf(position));
if (position == 0) {
return OverviewTab1Fragment.instantiate(context, productDataContent);
} else if (position == 1) {
return OverviewTab2Fragment.instantiate(context, productDataContent);
} else if (position == 2) {
return OverviewTab3Fragment.instantiate(context, productDataContent);
}
return OverviewTab1Fragment.instantiate(context, productDataContent);
}
UPDATE
This is an example with Fragment in Array:
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.util.SparseArray;
import android.view.ViewGroup;
public class TabsViewPagerAdapter extends FragmentStatePagerAdapter {
private CharSequence titlesArray[]; // This will Store the Titles of the Tabs which are Going to be passed when TabsViewPagerAdapter is created
private Fragment tabsArray[];
private SparseArray<Fragment> registeredFragments;
// Build a Constructor and assign the passed Values to appropriate values in the class
public TabsViewPagerAdapter(FragmentManager fm, CharSequence titlesArray[], Fragment[] tabsArray) {
super(fm);
this.titlesArray = titlesArray;
this.tabsArray = tabsArray;
this.registeredFragments = new SparseArray<>();
}
//This method return the fragment for the every position in the View Pager
#Override
public Fragment getItem(int position) {
return tabsArray[position];
}
// This method return the titles for the Tabs in the Tab Strip
#Override
public CharSequence getPageTitle(int position) {
return titlesArray[position];
}
// This method return the Number of tabs for the tabs Strip
#Override
public int getCount() {
return titlesArray.length;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
public Fragment getRegisteredFragment(int position) {
return registeredFragments.get(position);
}
}
In the Java you create the adapter:
String[] tabTitles = new String[]{"Tab1", "Tab2", "Tab3"};
Fragment[] tabsArray = new Fragment[]{new OverviewTab1Fragment(), new OverviewTab2Fragment(), new OverviewTab3Fragment()};
adapter = new TabsViewPagerAdapter(getSupportFragmentManager(), tabTitles, tabsArray);
And the fragment is something like this:
import android.support.v4.app.Fragment;
public class OverviewTab1Fragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.yourFragmentLayout, container, false);
return v;
}
}
I hope help you.
Related
I am creating an app that has 3 Tabs and every tabs has a different jobs. For Example, In Employee tab, there are EditText for taking name and surname of an emolyee and Button for add items to the its RecyclerView. City Tab is same as Employee tab just takes city names. The last tab has only one Button for distribute entries of Employees and Cities and show to user.
My problem is, I cannot find how to add items to the RecyclerView and and show it to the user.
Here is my code. I am sending just Tab1's fragment and layouts. Others are the same.
This is the Fragment1 class:
public class Fragment1 extends Fragment {
private RecyclerView employeeRecyclerView;
private RecyclerViewAdapter employeeRecyclerViewAdapter;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.name_employee, container, false);
}
}
This is the RecyclerViewAdapter class:
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder>{
private List<String> mData;
private LayoutInflater mInflater;
RecyclerViewAdapter(Context context, List<String> data) {
this.mInflater = LayoutInflater.from(context);
this.mData = data;
}
#NonNull
#Override
public RecyclerViewAdapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.fragment_main, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull RecyclerViewAdapter.ViewHolder holder, int position) {
String x = mData.get(position);
holder.myTextView.setText(x);
}
#Override
public int getItemCount() {
return mData.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
TextView myTextView;
ViewHolder(View itemView) {
super(itemView);
myTextView = itemView.findViewById(R.id.section_label);
}
}
}
and Employee.xml file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="#+id/employeeField"
android:hint="Name and Surname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" />
<Button
android:id="#+id/cityAdd"
android:text="addEmployee"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/employees"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
and fragment_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/constraintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.main.PlaceholderFragment">
<TextView
android:id="#+id/section_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Update I upload other classes. There are Fragment2 and Fragment3 classes but they are same with Fragment1.
PlaceHolderFragment.class
public class PlaceholderFragment extends Fragment {
private static final String ARG_SECTION_NUMBER = "section_number";
private PageViewModel pageViewModel;
public static PlaceholderFragment newInstance(int index) {
PlaceholderFragment fragment = new PlaceholderFragment();
Bundle bundle = new Bundle();
bundle.putInt(ARG_SECTION_NUMBER, index);
fragment.setArguments(bundle);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
pageViewModel = ViewModelProviders.of(this).get(PageViewModel.class);
int index = 1;
if (getArguments() != null) {
index = getArguments().getInt(ARG_SECTION_NUMBER);
}
pageViewModel.setIndex(index);
}
#Override
public View onCreateView(
#NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_main, container, false);
final TextView textView = root.findViewById(R.id.section_label);
pageViewModel.getText().observe(this, new Observer<String>() {
#Override
public void onChanged(#Nullable String s) {
textView.setText(s);
}
});
return root;
}
}
SectionsPagerAdapter.class
public class SectionsPagerAdapter extends FragmentPagerAdapter {
#StringRes
private static final int[] TAB_TITLES = new int[]{R.string.tab_text_1, R.string.tab_text_2, R.string.tab_text_3};
private final Context mContext;
public SectionsPagerAdapter(Context context, FragmentManager fm) {
super(fm);
mContext = context;
}
#Override
public Fragment getItem(int position) {
Fragment fragment = null;
switch (position){
case 0:
fragment = new Fragment1();
break;
case 1:
fragment = new Fragment2();
break;
case 2:
fragment = new Fragment3();
break;
}
return fragment;
}
#Nullable
#Override
public CharSequence getPageTitle(int position) {
return mContext.getResources().getString(TAB_TITLES[position]);
}
#Override
public int getCount() {
return 3;
}
}
and PageViewModel.class
public class PageViewModel extends ViewModel {
private MutableLiveData<Integer> mIndex = new MutableLiveData<>();
private LiveData<String> mText = Transformations.map(mIndex, new Function<Integer, String>() {
#Override
public String apply(Integer input) {
return "Hello world from section: " + input;
}
});
public void setIndex(int index) {
mIndex.setValue(index);
}
public LiveData<String> getText() {
return mText;
}
}
I want to display Fragments in a ViewPager however it is only showing the first Fragment in the view tabs. The only fragment that gets shown is the one returned at postion 0 in the getItem(0 method - this fragment is displayed in subsequent views.
FragmentPagerAdapter:
public class SimpleFragmentPagerAdapter extends FragmentPagerAdapter {
public SimpleFragmentPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
if (position == 0) {
return new WorldFragment();
} else if (position == 1) {
return new PoliticsFragment();
} else if (position == 2) {
return new TechnologyFragment();
} else if (position == 3) {
return new ScienceFragment();
} else if (position == 4) {
return new SportsFragment();
} else if (position == 5) {
return new FoodFragment();
} else if (position == 6) {
return new TravelFragment();
} else if (position == 7) {
return new MoviesFragment();
} else if (position == 8) {
return new FashionFragment();
} else {
return new OpinionFragment();
}
}
#Override
public int getCount() {
return 10;
}
}
Fragment:
public class WorldFragment extends Fragment implements LoaderManager.LoaderCallbacks<List<Story>> {
public static final String LOG_TAG = WorldFragment.class.getName();
private static final String NY_TIMES_REQUEST_URL = "https://api.nytimes.com/svc/topstories/v2/world.json?api-key=<API KEY REMOVED>;
private StoryAdapter mAdapter;
private TextView mEmptyTextView;
private View rootView;
public WorldFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.story_list, container, false);
mAdapter = new StoryAdapter(getActivity(), new ArrayList<Story>());
final ListView listView = (ListView) rootView.findViewById(R.id.story_list);
mEmptyTextView = (TextView) rootView.findViewById(R.id.empty_textview);
listView.setEmptyView(mEmptyTextView);
listView.setAdapter(mAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
Story currentStory = mAdapter.getItem(position);
String url = currentStory.getmURL();
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
}
});
ConnectivityManager cm = (ConnectivityManager) getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
boolean isConnected = activeNetwork != null && activeNetwork.isConnectedOrConnecting();
if (isConnected) {
LoaderManager loaderManager = getActivity().getLoaderManager();
loaderManager.initLoader(0, null, this);
} else {
View loadingIndicator = rootView.findViewById(R.id.loading_indicator);
loadingIndicator.setVisibility(View.GONE);
mEmptyTextView = (TextView) rootView.findViewById(R.id.empty_textview);
mEmptyTextView.setText(R.string.no_internet_connection);
}
return rootView;
}
#Override
public android.content.Loader<List<Story>> onCreateLoader(int i, Bundle bundle) {
return new StoryLoader(getActivity(), NY_TIMES_REQUEST_URL);
}
#Override
public void onLoadFinished(android.content.Loader<List<Story>> loader, List<Story> stories) {
mAdapter.clear();
View loadingIndicator = rootView.findViewById(R.id.loading_indicator);
loadingIndicator.setVisibility(View.GONE);
mEmptyTextView.setText(R.string.no_new_stories);
if (stories != null && !stories.isEmpty()) {
mAdapter.addAll(stories);
}
}
#Override
public void onLoaderReset(android.content.Loader<List<Story>> loader) {
mAdapter.clear();
}
#Override
public void onStop() {
super.onStop();
}
}
ViewPager XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.android.topworldstories.MainActivity">
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
List XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:layout_height="match_parent">
<ListView
android:id="#+id/story_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:drawSelectorOnTop="true" />
<TextView
android:id="#+id/empty_textview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:visibility="gone"
tools:text="No new stories"/>
<ProgressBar
android:id="#+id/loading_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:layout_centerInParent="true"/>
</LinearLayout>
I am unsure of what is causing this. Any help is appreciated
it is only showing the first Fragment multiple times in the view tabs
Two possibilities I see, both of which are copy-paste errors.
1) You didn't change this URL (notice world.json)
private static final String NY_TIMES_REQUEST_URL = "https://api.nytimes.com/svc/topstories/v2/world.json?api-key=<API KEY REMOVED>";
2) You didn't use a different layout.
rootView = inflater.inflate(R.layout.story_list, container, false);
But since your data seems to be consistent, I'm guessing #1 is true.
If you have 10 different URL's that you want to display in the same "fragment layout", you do not need 10 separate Fragment files.
For example, one Fragment
public class NyTimesFragment extends Fragment implements LoaderManager.LoaderCallbacks<List<Story>> {
public static final String LOG_TAG = NyTimesFragment.class.getName();
private static final String NY_TIMES_URL = "nyTimesURL";
private StoryAdapter mAdapter;
private TextView mEmptyTextView;
private View rootView;
public NyTimesFragment(String url) {
Bundle b = new Bundle();
b.putExtra(NY_TIMES_URL, url); // Pass URL here
setArguments(b);
}
public NyTimesFragment() {
// Required empty public constructor
}
#Override
public android.content.Loader<List<Story>> onCreateLoader(int i, Bundle bundle) {
// Load url here
String url = getArguments().getString(NY_TIMES_URL);
return new StoryLoader(getActivity(), url);
}
That you pass any NyTimes URL to
public class SimpleFragmentPagerAdapter extends FragmentPagerAdapter {
// List of NyTimes topics
private String[] topics = { "world", "politics" };
// !!! Do NOT store this in your app... !!!
private static final String API_KEY = "XXXXX";
public SimpleFragmentPagerAdapter(FragmentManager fm) {
super(fm);
}
private String getURL(String apiKey, String topic) {
return String.format(
"https://api.nytimes.com/svc/topstories/v2/%s.json?api-key=%s",
topic, apiKey);
}
#Override
public int getCount() {
return topics.length; // Assuming each fragment goes to NyTimes
}
#Override
public Fragment getItem(int position) {
final String url = getURL(topics[position], API_KEY);
// Call the other constructor
return new NyTimesFragment(url);
} // done... no if statements.
Something to consider to make this somewhat better would be Retrofit + Gson...
Ok so the issue here is I was using the same loader id in initloader for each fragment & this is why the same data was being loaded. The loader id needs to be unique for each fragment for this to work.
I use ViewPager to create fragments that swipe left and now I want insert fragments into each fragment page.
activityMain.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
...
android:orientation="vertical">
<android.support.v4.view.ViewPager
android:id="#+id/myviewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
<devlight.io.library.ntb.NavigationTabBar
android:id="#+id/ntb_horizontal"
app:ntb_swiped="true"/>
</android.support.design.widget.CoordinatorLayout>
and this:
tab0_fragment.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:textSize="30sp"
android:gravity="center"
android:id="#+id/textView"
android:layout_centerHorizontal="true"
android:textColor="#android:color/holo_green_dark"
android:text="Social\nFragment"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:autoLink="web"
android:textSize="15sp"
android:layout_marginTop="10dp"
android:layout_centerHorizontal="true"
android:text="androidbelieve.com"
android:textColor="#000"
android:layout_below="#+id/textView"
android:textStyle="italic"/>
</RelativeLayout>
I have a ViewPager in mainActivity.java
final ViewPager viewPager = (ViewPager) findViewById(R.id.myviewpager);
viewPager.setAdapter(new PagerAdapter() {
...
...
}
I try open one screen in viewpager via fragment layout.
I try this:
final ViewPager viewPager = (ViewPager) findViewById(R.id.myviewpager);
viewPager.setAdapter(new PagerAdapter() {
...
public Object instantiateItem(final ViewGroup container, final int position) {
if (position == 0)
{
final View view = LayoutInflater.from(getBaseContext()).inflate(R.layout.fragment_tab0, null, false);
FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.myviewpager,new tab0Fragment()).commit();
container.addView(view);
return view;
}
else if (position == 1)
...
}
...
}
AND tab0Fragment.java
public class tab0Fragment extends Fragment {
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_tab0,null);
}
}
I am noob in android. how can correct this code?
Solution:
The answers was not my answer but that help me a lot.
According #Mr. Rabbit ans #Amit Upadhyay I change top code to this:
#Override
public Object instantiateItem(final ViewGroup container, final int position) {
if (position == 0)
{
final View view = LayoutInflater.from(getBaseContext()).inflate(R.layout.fragment_tab0, null, false);
MyAdapter adapter = new MyAdapter(getSupportFragmentManager());
adapter.addFragment(new tab0Fragment(), getResources().getString(R.string.tab0));
container.addView(view);
return view;
}
else if (position == 1)
{
and also adding MyAdapter class according #Mr. Rabbit's answer.
hope help someone else.
Try to separate out your adapter and below code.
MyAdapter.java
public class MyAdapter extends FragmentPagerAdapter{
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public MyAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
Create your Fragments
FragmentOne.java
public class FragmentOne extends Fragment {
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_one, container, false);
return view;
}
}
FragmentTwo.java
public class FragmentTwo extends Fragment {
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_two, container, false);
return view;
}
}
Setup your viewpager like this in your activity.
final ViewPager viewPager = (ViewPager) findViewById(R.id.myviewpager);
MyAdapter adapter = new MyAdapter(getSupportFragmentManager());
// Add your fragments in adapter.
FragmentOne fragmentOne = new FragmentOne();
adapter.addFragment(fragmentOne, getResources().getString(R.string.fragment_one_title));
FragmentTwo fragmentTwo = new FragmentTwo();
adapter.addFragment(fragmentTwo, getResources().getString(R.string.fragment_two_title));
viewPager.setAdapter(adapter);
Then finally set your NavigationTabBar with your ViewPager.
final NavigationTabBar navigationTabBar = (NavigationTabBar) findViewById(R.id.ntb_horizontal);
navigationTabBar.setViewPager(viewPager, 2);
To achieve this you can create a custom ViewPagerAdapter. Eg:
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import java.util.ArrayList;
/**
* Created by aupadhyay on 1/5/17.
*/
public class ViewPagerAdapter extends FragmentPagerAdapter {
ArrayList<Fragment> fragments = new ArrayList<>();
ArrayList<String> tabTitles = new ArrayList<>();
public void addFragments(Fragment fragment, String tabTitle)
{
this.fragments.add(fragment);
this.tabTitles.add(tabTitle);
}
public ViewPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
return fragments.get(position);
}
#Override
public int getCount() {
return fragments.size();
}
#Override
public CharSequence getPageTitle(int position) {
return tabTitles.get(position);
}
}
Now you can set adapter on viewpager like this:
final ViewPager viewPager = (ViewPager) findViewById(R.id.myviewpager);
ViewPagerAdapter viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager());
viewPagerAdapter.addFragments(new Tab0Fragment(), "First");
viewPagerAdapter.addFragments(new Tab1Fragment(), "Second");
viewPagerAdapter.addFragments(new Tab2Fragment(), "Third");
// add more if required.
viewPager.setAdapter(viewPagerAdapter);
Tab0Fragment, Tab1Fragment, Tab1Fragment are the fragments created by you to add in your viewpager.
I am trying to pass an object that is retrieved and created during my main activities on create method to one of the fragments of my sliding tabs layout.
Since this object is created over a network connection my plan was to receive the data during the creation of the Main Activity then pass the resulting object to my fragments. However this seems easier said than done. The resulting object will then get passed to a recycler view in the Forecast fragment.
I have read various methods including implementing the parcelable interface on my model object, storing it as a bundle and trying to send it over to the fragment. However it always came up null. I believe this was due to me creating a new fragment in memory and not passing the bundle to the fragment that was displayed. I also don't have any ID's for the fragments so locating them by ID isn't possible, at least to my knowledge.
If anyone could point me in the right direction Id be greatly appreciative.
Main Activity.java
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MAIN ACTIVITY";
#Bind(R.id.toolBar) Toolbar mToolbar;
#Bind(R.id.viewPager) ViewPager mViewPager;
#Bind(R.id.tabLayout) SlidingTabLayout mTabLayout;
private ViewPagerAdapter mAdapter;
private String mForecastsTabName = "Forecasts";
private String mAlertsTabName = "Alerts";
private String mTabTitles[] = {mForecastsTabName, mAlertsTabName};
private int mNumberOfTabs = 2;
private Forecast[] mForecasts;
private JsonParser mJsonParser = new JsonParser();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
setSupportActionBar(mToolbar);
setupSlidingTabs();
}
private void setupSlidingTabs() {
// Creating The ViewPagerAdapter and Passing Fragment Manager, Titles fot the Tabs and Number Of Tabs.
mAdapter = new ViewPagerAdapter(getSupportFragmentManager(), mTabTitles, mNumberOfTabs);
// Assigning the ViewPages View and setting the adapter
mViewPager.setAdapter(mAdapter);
// Assigning the Sliding Tab Layout View
mTabLayout.setDistributeEvenly(true); // To make the Tabs Fixed set this true, This makes the tabs Space Evenly in Available width
// Setting Custom Color for the Scroll bar indicator of the Tab View
mTabLayout.setCustomTabColorizer(new SlidingTabLayout.TabColorizer() {
#Override
public int getIndicatorColor(int position) {
return getResources().getColor(R.color.ColorAccent);
}
});
mTabLayout.setViewPager(mViewPager);
}
Forecast Fragment.java
public class ForecastFragment extends Fragment {
private static final String FORECAST_KEY = "FORECAST_KEY";
private static final String TAG = "FRAGMENT";
private Forecast[] mForecasts;
#Bind(R.id.recyclerView) RecyclerView mRecyclerView;
#Bind(R.id.emptyView) TextView mEmptyView;
#Bind(R.id.locationButton) Button mLocationButton;
public static ForecastFragment newInstance(Forecast[] forecasts) {
ForecastFragment fragment = new ForecastFragment();
Bundle bundle = new Bundle();
bundle.putParcelableArray(FORECAST_KEY, forecasts);
fragment.setArguments(bundle);
return fragment;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Initialize dataset, this data would usually come from a local content provider or
// remote server.
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.forecast_tab_fragment, container, false);
ButterKnife.bind(this, view);
displayEmptyViewIfNoData();
ForecastAdapter adapter = new ForecastAdapter(getActivity(), mForecasts);
mRecyclerView.setAdapter(adapter);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(layoutManager);
return view;
}
private void displayEmptyViewIfNoData() {
if (mForecasts == null || mForecasts.length < 1) {
mRecyclerView.setVisibility(View.GONE);
mEmptyView.setVisibility(View.VISIBLE);
mLocationButton.setVisibility(View.VISIBLE);
}
else {
mRecyclerView.setVisibility(View.VISIBLE);
mEmptyView.setVisibility(View.GONE);
mLocationButton.setVisibility(View.GONE);
}
}
#OnClick(R.id.locationButton)
public void selectLocations(View view) {
Intent intent = new Intent(getActivity(), LocationSelectionActivity.class);
intent.putExtra(ActivityConstants.CALLING_ACTIVITY, ActivityConstants.FORECAST_ACTIVITY);
startActivity(intent);
}
}
ViewPagerAdapter.java
public class ViewPagerAdapter extends FragmentStatePagerAdapter {
// This will Store the Titles of the Tabs which are Going to be passed when ViewPagerAdapter is created
String mTitles[];
// Store the number of tabs, this will also be passed when the ViewPagerAdapter is created
int mNumberOfTabs;
SparseArray<Fragment> registeredFragments = new SparseArray<>();
public ViewPagerAdapter(FragmentManager fm, String titles[], int numberOfTabs) {
super(fm);
mTitles = titles;
mNumberOfTabs = numberOfTabs;
}
//This method return the fragment for the every position in the View Pager
#Override
public Fragment getItem(int position) {
if (position == 0) {
ForecastFragment forecastFragment = new ForecastFragment();
return forecastFragment;
}
else if (position == 1) {
AlertFragment alertFragment = new AlertFragment();
return alertFragment;
}
return null;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
public Fragment getRegisteredFragment(int position) {
return registeredFragments.get(position);
}
// This method return the titles for the Tabs in the Tab Strip
#Override
public CharSequence getPageTitle(int position) {
return mTitles[position];
}
#Override
public int getCount() {
return mNumberOfTabs;
}
}
Forecast_tab_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/ColorPrimaryLight">
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="#dimen/activity_vertical_margin"/>
<TextView
android:id="#+id/emptyView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/empty_forecast_message"
android:textColor="#color/ColorTextPrimary"
android:gravity="center"
android:visibility="gone"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginTop="115dp"/>
<Button
android:id="#+id/locationButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/button_shape"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:textColor="#color/ColorTextPrimary"
android:text="#string/add_forecast_button"
android:visibility="gone"
android:layout_alignParentBottom="false"
android:layout_centerHorizontal="true"
android:layout_below="#+id/emptyView"
android:layout_marginTop="24dp"/>
</RelativeLayout>
When you do this code below, you can hand the data to your fragment.
In your Activity, call below, when the data is ready:
mAdapter.getFragment(index).setData(dataObject);
or
mAdapter.getFragment(mViewPager.getCurrentItem()).setData(dataObject);
Your FragmentPagerAdater should be like this:
class CustomPagerAdapter extends FragmentPagerAdapter {
SparseArray<App4StoreBaseSubFragment> registeredFragments = new SparseArray<App4StoreBaseSubFragment>();
public CustomPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
App4StoreBaseSubFragment fragment = (App4StoreBaseSubFragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
public ForecastFragment getFragment(int position){
return registeredFragments.get(position);
}
}
Your Fragment should be like this:
public class ForecastFragment extends Fragment {
public void setData(Forecast forecast){
//write code here to change UI
}
}
I'm trying to get this working: I basically want two Recyclerviews in one ViewPager. I followed this Tutorial: http://android-java-development.blogspot.de/2012/05/system.html, but it doesn't seem to work. I looks like the view pager is empty and the recycler view doesn't show up.
Here's my layout code:
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/pager_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="#dimen/tab_height">
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/accent"/>
</android.support.v4.widget.SwipeRefreshLayout>
And my PageAdapter:
public class NewsPagerAdapter extends PagerAdapter {
private Context context;
private Vector<RecyclerView> recyclerViewList;
private String[] titles;
public NewsPagerAdapter(Context context, int titlesId) {
this.context = context;
this.recyclerViewList = new Vector<>();
setTitles(titlesId);
}
public void add(RecyclerView recyclerView) {
recyclerViewList.add(recyclerView);
}
public RecyclerView.Adapter getAdapterForViewAtIndex(int index) {
return recyclerViewList.get(index).getAdapter();
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
container.addView(recyclerViewList.get(position),
new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 100)
);
return container;
}
#Override
public int getCount() {
return recyclerViewList.size();
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view.equals(object);
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
#Override
public CharSequence getPageTitle(int position) {
return titles[position];
}
public void setTitles(int titles) {
this.titles = context.getResources().getStringArray(titles);
}
}
And my onCreatView method:
GridLayoutManager layoutManager1 = new GridLayoutManager(getActivity(), getResources().getInteger(R.integer.news_column_count));
GridLayoutManager layoutManager2 = new GridLayoutManager(getActivity(), getResources().getInteger(R.integer.news_column_count));
RecyclerView listView1 = new RecyclerView(getActivity());
RecyclerView listView2 = new RecyclerView(getActivity());
listView1.setLayoutManager(layoutManager1);
listView2.setLayoutManager(layoutManager2);
NewsAdapter adapter1 = new NewsAdapter(getActivity(), null);
NewsAdapter adapter2 = new NewsAdapter(getActivity(), null);
adapter1.setOnItemClickListener(this);
adapter2.setOnItemClickListener(this);
listView1.setAdapter(adapter1);
listView2.setAdapter(adapter2);
newsPagerAdapter.add(listView1);
newsPagerAdapter.add(listView2);
newsViewPager.setAdapter(newsPagerAdapter);
Here I'm passing the cursor object to the adapter:
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
((NewsAdapter) newsPagerAdapter.getAdapterForViewAtIndex(0)).swapCursor(data);
}
You have to extend FragmentPagerAdapter or FragmentStatePagerAdapter in order to easily embed RecyclerView. If you are going to update your ViewPager contents during its lifecycle it is strictly recommended to use FragmentStatePagerAdapter
You will have to create additional fragment layout, containing RecyclerView.
If you wish to update your ViewPager with SwipeRefreshLayout, don't wrap it with SwipeRefreshLayout. Instead, you must have SwipeRefreshLayout inside fragment layout.
Therefore for your fragment you may get the following xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/listRefresh"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/categoryList"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.v4.widget.SwipeRefreshLayout>
And create additional Fragment class, which will inflate that layout and implement methods, that you will need to update refresh indicator status.
A bit old example is found here:
http://developer.android.com/training/implementing-navigation/lateral.html
If you wish to connect your ViewPager with new support library TabLayout, it is easily one with:
tabLayout.setupWithViewPager(viewPager);
Finally, if you will update your "fragmented" ViewPager, don't try to reset the adapter, as fragments are managed not with adapter, but with FragmentManager. It is wiser to update content of corresponding RecyclerViews
public class MyFragmentedPagerAdapter extends FragmentStatePagerAdapter {
private final TabLayout mTabLayout;
private final SwipeRefreshLayout.OnRefreshListener mRefreshListener;
private Vector<PriceListFragment> fragmentList;
private Vector<String> titles;
public MyFragmentedPagerAdapter(FragmentManager fm, MyComplexData data, OnCartActionListener listener, TabLayout tabLayout, SwipeRefreshLayout.OnRefreshListener refreshListener) {
super(fm);
mTabLayout = tabLayout;
// external refresh listener, that will trigger an updateData()
mRefreshListener = refreshListener;
fragmentList = new Vector<>();
titles = new Vector<>();
updateData(data);
}
public void updateData(MyComplexData data) {
boolean updateTabs = false;
boolean hasNewData = false;
Vector<String> newTitles = new Vector<>();
int position = 0;
for(TabContents tabContents : data.getTabContents()) {
if(tabContents.getListContents() == null)
continue;
hasNewData = true;
boolean isNewFragment;
MyFragment fragment;
try {
fragment = fragmentList.get(position);
isNewFragment = false;
} catch (ArrayIndexOutOfBoundsException e) {
fragment = new MyFragment();
isNewFragment = true;
}
// Update the data, title and hide update indicator of SwipeRefreshLayout
fragment.setTabContents(tabContents);
newTitles.add(tabContents.getName());
if(isNewFragment) {
fragment.setRefreshListener(mRefreshListener);
fragmentList.add(fragment);
}
position++;
}
if(!hasNewData)
return;
// we need to decide, whether to update tabs
if(titles.size() != newTitles.size()) {
updateTabs = true;
} else {
for(position = 0; position < titles.size(); position++) {
if(!titles.get(position).equals(newTitles.get(position))) {
updateTabs = true;
break;
}
}
}
titles = newTitles;
notifyDataSetChanged();
if(updateTabs)
mTabLayout.setTabsFromPagerAdapter(this);
}
#Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}
// You need to override this method as well
#Override
public int getItemPosition(Object object) {
MyFragment fragment = (MyFragment) object;
String title = (String) fragment.getTitle();
int position = titles.indexOf(title);
if (position >= 0) {
return position;
} else {
return POSITION_NONE;
}
}
#Override
public int getCount() {
return titles.size();
}
#Override
public CharSequence getPageTitle(int position) {
return fragmentList.get(position).getTitle();
}
}
Your MyFragment class has to implement getTitle() method.