Android TabLayout ViewPager not inflating tab fragment on backstack - android

I've got a tab view set up that that has custom fragments for each tab using a viewpager. This is my code:
Holding Fragment
public class FragInboxMainView extends Fragment implements CGFragment {
private CGController controller;
private CGFragment thisFragment;
#Bind(R.id.inboxViewPager)ViewPager inboxViewPager;
#Bind(R.id.inboxTabs)TabLayout inboxTabLayout;
#Bind(R.id.inbox_progress_wheel)ProgressWheel inboxProgressWheel;
public FragInboxMainView(){}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_inbox_mainview, container, false);
ButterKnife.bind(this, rootView);
thisFragment = this;
Globals g = Globals.getInstance();
/** Show loading spinner */
this.inboxProgressWheel.setBarColor(ContextCompat.getColor(controller.getContext(), g.getUserObject().getUserThemeColor()));
this.inboxProgressWheel.setVisibility(View.VISIBLE);
/** Display the profile information based off the ID */
controller.displayInbox(thisFragment);
return rootView;
}
public void hideProgressSpinner() {
this.inboxProgressWheel.setVisibility(View.GONE);
}
public ViewPager getInboxViewPager() {
return this.inboxViewPager;
}
public TabLayout getInboxTabLayout() {
return this.inboxTabLayout;
}
}
Its layout file
<?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:wheel="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.TabLayout
android:id="#+id/inboxTabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="scrollable" />
<com.pnikosis.materialishprogress.ProgressWheel
android:id="#+id/inbox_progress_wheel"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_gravity="center"
wheel:matProg_barColor="#5588FF"
wheel:matProg_progressIndeterminate="true"
android:visibility="gone"/>
<android.support.v4.view.ViewPager
android:id="#+id/inboxViewPager"
android:layout_width="match_parent"
android:layout_height="0px"
android:layout_weight="1"
android:background="#android:color/white" />
</LinearLayout>
Tab fragment and its inflation file
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
android:id="#+id/main_content"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.baoyz.widget.PullRefreshLayout
android:id="#+id/tabPullRefresh"
android:layout_width="match_parent"
android:layout_height="match_parent">
<view
android:id="#+id/tabRecyclerHolder"
class="android.support.v7.widget.RecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:clipToPadding="false"
android:layout_centerInParent="true"/>
</com.baoyz.widget.PullRefreshLayout>
<com.melnykov.fab.FloatingActionButton
android:id="#+id/tabFab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:layout_margin="16dp"
android:src="#mipmap/ic_add_white"/>
</android.support.design.widget.CoordinatorLayout>
public class TabRecyclerHolder extends Fragment {
#Bind(R.id.tabRecyclerHolder) RecyclerView tabRecyclerHolder;
#Bind(R.id.tabPullRefresh) PullRefreshLayout tabPullRefresh;
#Bind(R.id.tabFab) FloatingActionButton recyclerFab;
private String tabTitle = "Title";
public TabRecyclerHolder(){}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.tab_recycler_holder, container, false);
ButterKnife.bind(this, rootView);
recyclerFab.hide(false);
tabPullRefresh.setRefreshStyle(PullRefreshLayout.STYLE_MATERIAL);
return rootView;
}
public RecyclerView getTabRecyclerHolder() {
return this.tabRecyclerHolder;
}
public FloatingActionButton getRecyclerFab() {
return this.recyclerFab;
}
public String getTabTitle() {
return this.tabTitle;
}
public void setTabTitle(String title) {
this.tabTitle = title;
}
public PullRefreshLayout getTabPullRefresh() {
return this.tabPullRefresh;
}
}
My tab adapter
public class TabPagerAdapter extends FragmentStatePagerAdapter {
private CGController controller;
private List<Object> items;
public TabPagerAdapter(FragmentManager fm, CGController controller, List<Object> items) {
super(fm);
this.controller = controller;
this.items = items;
}
#Override
public int getCount() {
return items.size();
}
#Override
public Fragment getItem(int num) {
return (TabRecyclerHolder)items.get(num);
}
#Override
public String getPageTitle(int num){
return ((TabRecyclerHolder)items.get(num)).getTabTitle();
}
}
The processing code
public void viewInbox() {
/** Set up the views */
receivedHolder = new TabRecyclerHolder();
receivedHolder.setTabTitle(Constants.TAB_INBOX_RECEIVED);
sentHolder = new TabRecyclerHolder();
sentHolder.setTabTitle(Constants.TAB_INBOX_SENT);
tabs.add(receivedHolder);
tabs.add(sentHolder);
/** Set up the tabs */
final ViewPager inboxViewPager = inboxFragment.getInboxViewPager();
TabLayout inboxTabLayout = inboxFragment.getInboxTabLayout();
/** Set the adapter for the view pager */
inboxViewPager.setAdapter(new TabPagerAdapter(inboxFragment.getChildFragmentManager(), controller, tabs));
/** set up the tab look and feel */
inboxTabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
inboxTabLayout.setTabMode(TabLayout.MODE_FIXED);
inboxViewPager.setOffscreenPageLimit(3);
inboxViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(inboxTabLayout));
inboxTabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
inboxViewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
/** And, display! */
inboxTabLayout.setupWithViewPager(inboxViewPager);
receivedAdapter = new RecyclerListAdapter(controller, items);
final RecyclerView receivedList = receivedHolder.getTabRecyclerHolder();
receivedList.setLayoutManager(new LinearLayoutManager(controller.getContext()));
receivedList.setAdapter(receivedAdapter);
}
There is some code i've missed out but its not pertanent to the question.
The code works perfectly when initially viewing the fragment. However since my application contains a single activity and just replaces a content view for each fragment navigated to, each fragment is added to the back stack and then popped when the back button is pressed. My issue is that when navigating back to this fragment the view inside the tab isn't being inflated, which means that no elements can be accessed (and therefore the app crashes while trying to display the data in the recyclerview etc).
I have had a look at this question: TabLayout ViewPager Not Loading When Using Backstack and implemented its suggestion (using getChildFragmentManager() when setting up the pager adapter) however that has not fixed my issue.
Help would be appreciated!

Change this public View onCreateView(LayoutInflater inflater,... to public void onViewCreated (View view, Bundle savedInstanceState)
so you are going to have something like this
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.tab_recycler_holder, container, false);
}
then
#Override
public void onViewCreated (View view, Bundle savedInstanceState){
ButterKnife.bind(this, view);
recyclerFab.hide(false);
tabPullRefresh.setRefreshStyle(PullRefreshLayout.STYLE_MATERIAL);
...
see if it helps

Extend FragmentStatePagerAdapter in TabPagerAdapter as
FragmentStatePagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT)

Related

Unable to view fragments in ViewPager

I've been recently working on a project and I have tried using ViewPager for the first time. Unfortunately, something is not going as expected. I have created my ViewPagerAdapter:
public class ViewPagerAdapter extends FragmentPagerAdapter {
private List<Fragment> fragmentList = new ArrayList<>();
private List<String> stringList = new ArrayList<>();
public ViewPagerAdapter(#NonNull FragmentManager fm) {
super(fm);
}
public ViewPagerAdapter(#NonNull FragmentManager fm, int behavior) {
super(fm, behavior);
}
#NonNull
#Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}
#Override
public int getCount() {
return fragmentList.size();
}
#Nullable
#Override
public CharSequence getPageTitle(int position) {
return stringList.get(position);
}
public void addFragment(Fragment fragment, String title) {
fragmentList.add(fragment);
stringList.add(title);
}
There are multiple fragments handled in the activity by the adapter.
public class PatientActivity extends AppCompatActivity {
#BindView(R.id.tab_layout)
TabLayout tabLayout;
#BindView(R.id.view_pager_pacient_view)
ViewPager viewPager;
ActivityPatientBinding binding;
ViewPagerAdapter viewPagerAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityPatientBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
ButterKnife.bind(this);
setupViewPager();
}
private void setupViewPager() {
//getChildFragmentManager?
viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager());
viewPagerAdapter.addFragment(PatientDetailsFragment.newInstance(), "Pacient");
viewPagerAdapter.addFragment(StateFragment.newInstance(), "Stare");
viewPagerAdapter.addFragment(PathologicalBackgroundFragment.newInstance(), "Antecedente");
viewPagerAdapter.addFragment(TriageFragment.newInstance(), "Triaj");
viewPagerAdapter.addFragment(EkgFragment.newInstance(), "Observatii");
viewPagerAdapter.addFragment(AnalysisFragment.newInstance(), "Analize");
viewPagerAdapter.addFragment(RecommendationFragment.newInstance(), "Recomandari");
viewPager.setAdapter(viewPagerAdapter);
tabLayout.setupWithViewPager(viewPager);
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(viewPager));
}
}
And the xml belonging to the activity is this one
<?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:fitsSystemWindows="true"
android:background="?android:windowBackground"
tools:context=".ui.addpatientpage.PatientActivity"
android:orientation="horizontal">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/white"
android:theme="#style/AppTheme.AppBarOverlay"
app:elevation="0dp">
<com.google.android.material.tabs.TabLayout
android:id="#+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/transparent"
android:paddingHorizontal="#dimen/spacing_medium"
app:tabBackground="#android:color/transparent"
app:tabGravity="center"
app:tabIndicator="#drawable/shape_rounded_red"
app:tabIndicatorColor="#color/colorNavigation"
app:tabIndicatorGravity="center"
app:tabIndicatorHeight="#dimen/spacing_xlarge"
app:tabMinWidth="120dp"
app:tabRippleColor="#android:color/transparent"
app:tabSelectedTextColor="#android:color/white"
app:tabTextAppearance="#style/TextAppearance.AppCompat.Body2"
app:tabTextColor="#color/grey_60">
</com.google.android.material.tabs.TabLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager.widget.ViewPager
android:id="#+id/view_pager_pacient_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
sample of the Fragment:
public class PatientDetailsFragment extends Fragment {
public static PatientDetailsFragment newInstance() {
return new PatientDetailsFragment();
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.row_pacient_details, container, false);
ButterKnife.bind(this, root);
return root;
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
}
Should I override the method onViewCreated in each fragment to make the visible?
I have looked at the code multiple times and tried different solutions, I have even tried to implement it with ViewPager2, but nothing seems to work. It feels like there is a small fix that is needed, but after many hours of trying, I came to the conclusion that I can not find it by myself. Can you please also take a look and eventually give me a hint? Should I override the method onViewCreated in each fragment to make the visible or do you see some other issue in here?
If the adapter seems to contain all of the fragments specified in the main class, where can it go wrong?

Items in RecyclerView in a Fragmnet don't appear

I saw there are similar post but my code is the same as the codes in the solutions so they weren't useful in my case. My app starts but and two tabs are shown. However the one that is supposed to show the items from a RecyclerView that's in it is empty.I also get this error:
E/RecyclerView: No adapter attached; skipping layout
So I have an Activity with a TabLayout and a ViewPager
public class MainActivity extends AppCompatActivity {
TabLayout tabLayout;
ViewPager viewPager;
PagerAdapter pagerAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tabLayout=findViewById(R.id.tab_layout);
viewPager=findViewById(R.id.view_pager);
tabLayout.addTab(tabLayout.newTab().setText("CitiesFragment"));
tabLayout.addTab(tabLayout.newTab().setText("My CitiesFragment"));
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
pagerAdapter=new PagerAdapter(getSupportFragmentManager(),tabLayout.getTabCount());
viewPager.setAdapter(pagerAdapter);
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
}
}
This is a fragment with only a RecyclerView in it
public class CitiesFragment extends Fragment {
RecyclerView recyclerView;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View itemView = inflater.inflate(R.layout.cities_layout, container, false);
recyclerView = itemView.findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
List<City> data = Database.getDatabase();
CitiesAdapter adapter = new CitiesAdapter(data);
recyclerView.setAdapter(adapter);
return itemView;
}
}
This is the XML for the fragment
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
And this is the Adapter
public class CitiesAdapter extends RecyclerView.Adapter<CitiesVIewHolder> {
List<City> data;
private int itemCount;
public CitiesAdapter(List<City> data) {
this.data = data;
itemCount=data.size();
}
#NonNull
#Override
public CitiesVIewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.city_layout, viewGroup, false);
CitiesVIewHolder viewHolder = new CitiesVIewHolder(itemView);
return viewHolder;
}
#Override
public void onBindViewHolder(#NonNull CitiesVIewHolder citiesVIewHolder, int position) {
City city = data.get(position);
citiesVIewHolder.txtCityName.setText(city.getCityName());
citiesVIewHolder.txtCityInfo.setText(city.getCityInfo());
LoadImageTask loadImageTask = new LoadImageTask(citiesVIewHolder.imgCity);
loadImageTask.execute(city.getImageUrl());
}
#Override
public int getItemCount() {
return itemCount;
}
}
And the XML for the Adapter
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:id="#+id/img_city"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/txt_city_name"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/txt_city_info"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
My PagerAdapter only returns one of the two fragments(one of them is currently empty and the other on is with the RecyclerView)
public class PagerAdapter extends FragmentStatePagerAdapter {
private int itemCount;
public PagerAdapter(FragmentManager fm, int itemCount) {
super(fm);
this.itemCount = itemCount;
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new CitiesFragment();
case 1:
return new MyCitiesFragment();
default:
return null;
}
}
#Override
public int getCount() {
return itemCount;
}
}
I am sorry for the code overload but I really can not understand what I'm doing wrong. Thanks for the help in advance.
First of all your adapter xml root LinearLayout has height set to match_parent so change that to wrap_content.
Second one override onViewCreated and there set recyclerView not in onCreateView. For example:
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
recyclerView = view.findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerView.setHasFixedSize(true);
List<City> data = Database.getDatabase();
CitiesAdapter adapter = new CitiesAdapter(data);
recyclerView.setAdapter(adapter);
}
Also consider adding line: recyclerView.setHasFixedSize(true);
E/RecyclerView: No adapter attached; skipping layout
TabLayout display fragment with recyclerView but fragment takes more time to load datasource that makes recycler created without adapter attached.
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View itemView = inflater.inflate(R.layout.cities_layout, container, false);
recyclerView = itemView.findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
// List<City> data = Database.getDatabase(); // Don't fetch data on Main (UI) Thread
CitiesAdapter adapter = new CitiesAdapter(new ArrayList<City>()); //
recyclerView.setAdapter(adapter);
// Display city here one background and then update adapter.
return itemView;
}
If Datasource fetch data from local database then you can just use handler or postDelay on RecyclerView
recyclerView.postDelay(new Runnable(){
public void run(){
adapter.setCityList(result);
}
},500);
If you load data for server datasource the use background task, You can check this answer for fetch data from server with smooth way.
// load datasource inside Async Task.
new AsyncTaskHandler(new OnFinishCallback() {
#Override
public void onSuccess(List<City> result) {
adapter.setCityList(result);
}
}).execute("param that need to load datasource");
I have create a simple app to simulate your case.
RecyclerView width must be match_partent
<!--RecyclerView width must be match_parent-->
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content">
You can find the complete sample/CityPreview app on Github

Edittext automatically gets focus when move between pages in a view pager

I have an activity which hosts two fragments inside a view pager. I used the same layout to inflate those fragments. The layout has two edit texts placed inside a linear layout which is inside a relative layout. The problem is when I switch from fragment A to fragment B, he first edit text has focus in fragment A and when I return back from fragment B to fragment A, instead of the first edit text having focus, the second edit text gets the focus. How to solve it. I provide the layouts and source code below. I have not return any code inside the fragment classes.
Activity:
public class LoginActivity extends BaseActivity {
public static final String selectedTabPosition = "selectedTabPosition";
//Tab tag name
private static String TAB_1_TAG = "Email";
private static String TAB_2_TAG = "Mobile";
private TabLayout mTabLayout;
private ViewPager mViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
TAB_1_TAG = getResources().getString(R.string.tab_email);
TAB_2_TAG = getResources().getString(R.string.tab_mobile);
//Initialise views
mViewPager = (ViewPager) findViewById(R.id.viewpager);
mTabLayout = (TabLayout) findViewById(R.id.tabs);
//set tab with view pager
setupViewPager(mViewPager);
mTabLayout.setupWithViewPager(mViewPager);
setupTabIcons();
mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
dismissKeyboard(mViewPager);
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
}
/**
* Adding custom view to tab
*/
private void setupTabIcons() {
LinearLayout tabOne = (LinearLayout) LayoutInflater.from(this).inflate(R.layout.tab_custom, null);
TextView tvIconOne = (TextView) tabOne.findViewById(R.id.tv_tab_title);
tvIconOne.setText(TAB_1_TAG);
mTabLayout.getTabAt(0).setCustomView(tabOne);
setTypeface(tvIconOne, CustomFonts.Prime_regular);
mTabLayout.getTabAt(0).getCustomView().setSelected(true);
LinearLayout tabTwo = (LinearLayout) LayoutInflater.from(this).inflate(R.layout.tab_custom, null);
TextView tvIconTwo = (TextView) tabTwo.findViewById(R.id.tv_tab_title);
tvIconTwo.setText(TAB_2_TAG);
setTypeface(tvIconTwo, CustomFonts.Prime_regular);
mTabLayout.getTabAt(1).setCustomView(tabTwo);
}
/**
* Adding fragments to ViewPager
*
* #param viewPager The view pager
*/
private void setupViewPager(ViewPager viewPager) {
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
LoginFragment loginFragmentEmail = new LoginFragment();
Bundle emailBundle = new Bundle();
emailBundle.putInt(selectedTabPosition, 0);
loginFragmentEmail.setArguments(emailBundle);
LoginFragment loginFragmentMobile = new LoginFragment();
Bundle phoneBundle = new Bundle();
phoneBundle.putInt(selectedTabPosition, 1);
loginFragmentMobile.setArguments(phoneBundle);
adapter.addFrag(loginFragmentEmail, TAB_1_TAG);
adapter.addFrag(loginFragmentMobile, TAB_2_TAG);
viewPager.setAdapter(adapter);
}
class ViewPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public ViewPagerAdapter(FragmentManager manager) {
super(manager);
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
public void addFrag(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
}
Fragment:
public class LoginFragment extends BaseFragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View rootView = inflater.inflate(R.layout.fragment_login, container, false);
return rootView;
}
activity_login.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:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white"
android:orientation="vertical">
<ImageView
android:id="#+id/iv_title"
android:layout_width="200dp"
android:layout_height="45dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="30dp"
/>
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="#dimen/custom_tab_layout_height"
android:layout_below="#+id/iv_title"
android:layout_marginTop="#dimen/spacing_10"
app:tabGravity="fill"
app:tabIndicatorColor="#color/app_color_dark"
app:tabMode="fixed"/>
<View
android:id="#+id/view"
android:layout_width="match_parent"
android:layout_height="#dimen/divider_height_small"
android:layout_below="#+id/tabs"
android:background="#color/gray_medium"/>
<com.helper.CustomNonSwipeableViewpager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/view"
app:layout_behavior="#string/appbar_scrolling_view_behavior"/>
</RelativeLayout>
fragment_login.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="#android:color/white"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/spacing_50"
android:orientation="vertical">
<EditText
android:id="#+id/et_email"
android:layout_width="match_parent"
android:layout_height="#dimen/spacing_48"
/>
<EditText
android:id="#+id/et_password"
android:layout_width="match_parent"
android:layout_height="#dimen/spacing_48"
android:layout_marginTop="#dimen/spacing_15"/>
</LinearLayout>
</RelativeLayout>
AndroidManifest.xml:
<activity
android:name=".activities.LoginActivity"
android:screenOrientation="portrait"
/>
In the AndrodManifest file, tried the
android:windowSoftInputMode = stateHidden and android:windowSoftInputMode = adjustPan
CustomNonSwipeableViewpager.java:
public class CustomNonSwipeableViewpager extends ViewPager {
public CustomNonSwipeableViewpager(Context context) {
super(context);
}
public CustomNonSwipeableViewpager(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
// Never allow swiping to switch between pages
return false;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
// Never allow swiping to switch between pages
return false;
}
}
ScreenShots:
Before moving to FragmentB:
In Fragment B:
Return back to Fragment A from Fragment B:
You can disable the focus on the EditText during runtime of the fragment:
EditText et_email_view = (EditText) rootView.findViewById(R.id.et_email);
et_email_view.setFocusable(false);
Use requestFocus attribute to your first editText which will always cause that editText to gain focus.
Make following changes in your fragment_login.xml file,
<EditText
android:id="#+id/et_email"
android:layout_width="match_parent"
android:layout_height="#dimen/spacing_48">
<requestFocus />
</EditText>
For example in my case viewPager is covering editText. I set translationZ at editText(translationZ="2") and viewPage(translationZ="1") and it helped me.

Confusion about fragments and their activities

I have a TabLayout and ViewPager to hold and navigate between my fragments (3 of them) and that is working fine however I'm getting confused as to how I interact with each fragment for example button clicks or edit texts. Here is my main activity xml.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<android.support.design.widget.TabLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/tabLayout"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:background="#color/colorPrimary"
app:tabMode="fixed"
app:tabGravity="fill" />
<android.support.v4.view.ViewPager
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/viewPager"
android:layout_centerHorizontal="true"
android:layout_below="#+id/tabLayout" />
</RelativeLayout>
This is the activity for it.
public class ActivityMain extends AppCompatActivity {
private String tabTitles[] = new String[] { "contacts", "home", "search" };
TabLayout tabLayout;
ViewPager viewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
viewPager = (ViewPager) findViewById(R.id.viewPager);
viewPager.setAdapter(new CustomAdapater(getSupportFragmentManager(),getApplicationContext()));
tabLayout = (TabLayout) findViewById(R.id.tabLayout);
tabLayout.setupWithViewPager(viewPager);
tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
});
}
private class CustomAdapater extends FragmentPagerAdapter {
private String fragments [] = {"contacts", "home", "search"};
public CustomAdapater(FragmentManager supportFragmentManager, Context applicationContext) {
super(supportFragmentManager);
}
#Override
public Fragment getItem(int position) {
switch (position){
case 0:
return new FragmentContacts();
case 1:
return new FragmentMain();
case 2:
return new FragmentSearch();
default:
return null;
}
}
#Override
public int getCount() {
return fragments.length;
}
#Override
public CharSequence getPageTitle(int position) {
// Generate title based on item position
return tabTitles[position];
}
}
}
And here is a fragment activity.
public class FragmentSearch extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
return inflater.inflate(R.layout.fragment_search,container,false);
}
}
Now say in my R.layout.fragment_search I had a button just for examples sake, how do I set an onclicklistener for it? Is it within the FragmentSearch or ActivityMain? I've searched around but I'm just getting more confused.
You'd set your onClickListener in the fragment's onCreateView method by doing something like:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment1, container, false);
myButton = (Button) rootView.findViewById(R.id.buttonId);
myButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Perform action on click
}
});
return rootView;
}
Everything is the same regarding the onClickListener, as you can see. The only difference is that you have to inflate to view and use that view to find the appropriate components (e.g. buttons, textviews..)
Now, if you want to communicate between Fragments, you will need to implement more things. The basic way is to use interfaces to be implemented by your activity, so each fragment can call those methods within the activities.
There are also messaging libraries such as Otto and EventBus, they are great by sending stuff between not just fragments, but services also.

ViewPage Fragment disappear when reload again

The following is layout
test.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"
android:layout_height="match_parent">
<Button android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="Click"
android:id="#+id/button"
/>
<!-- Framelayout to display Fragments -->
<FrameLayout
android:id="#+id/frame_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
test_detail.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"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Hello"
android:id="#+id/textView" android:layout_gravity="center_horizontal"/>
</LinearLayout>
common_view_pager_layout
<?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">
<android.support.v4.view.ViewPager
android:id="#+id/MainViewerPage"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<android.support.v4.view.PagerTabStrip
android:id="#+id/TitlePageTabStrip"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.v4.view.ViewPager>
</LinearLayout>
The following is my Activity code
public class TestFragmentActivity extends FragmentActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.test);
Button button = (Button) this.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.frame_container, new HomeFragment()).commit();
}
});
}
public class HomeFragment extends Fragment {
private PagerAdapter _adapter;
public HomeFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.common_view_pager_layout, container, false);
this._adapter = new PagerAdapter(TestFragmentActivity.this);
this._adapter.add(new DetailFragment());
ViewPager pager = (ViewPager) view.findViewById(R.id.MainViewerPage);
pager.setAdapter(this._adapter);
return view;
}
}
public class DetailFragment extends Fragment {
public DetailFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.test_detail, container, false);
return rootView;
}
}
public class PagerAdapter extends FragmentPagerAdapter {
private ArrayList<Fragment> _fragments;
public PagerAdapter(FragmentActivity activity) {
super(activity.getSupportFragmentManager());
this._fragments = new ArrayList<Fragment>();
}
public void add(Fragment fragment) {
this._fragments.add(fragment);
}
#Override
public Fragment getItem(int position) {
return this._fragments.get(position);
}
#Override
public CharSequence getPageTitle(int position) {
return "Test";
}
#Override
public int getCount() {
return 1;
}
}
}
When I click a button the fragment in ViewPager was display
But when I click the button again the fragment disappear
Please help me.
try using this:
in the constructor of your adapter change this :
public class MyPagerAdapter extends FragmentPagerAdapter {
private ArrayList<Fragment> _fragments;
public MyPagerAdapter(FragmentManager activity) {
super(activity);
this._fragments = new ArrayList<Fragment>();
}
public void add(Fragment fragment) {
this._fragments.add(fragment);
}
#Override
public Fragment getItem(int position) {
return this._fragments.get(position);
}
#Override
public CharSequence getPageTitle(int position) {
return "Test";
}
#Override
public int getCount() {
return 1;
}
}
and when you want to create the adapter send getChildFragmentManager() to its constructor
public class HomeFragment extends Fragment {
private MyPagerAdapter _adapter;
public HomeFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.common_view_pager_layout, container, false);
ViewPager pager = (ViewPager) view.findViewById(R.id.MainViewerPage);
this._adapter = new MyPagerAdapter(getChildFragmentManager());
this._adapter.add(new DetailFragment());
pager.setAdapter(this._adapter);
return view;
}
}
I test it and it works, any problem comment it.
Good Luck!
In your Fragment class, in the onCreate() method, you have to call setRetainInstance(true) like this:
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
This tells the FragmentManager to keep your fragments on reloads.
In addition, check your manifest file doesn't have any
android:screenOrientation
config changes where you are basically saying you will handle reloads due to config changes yourself.
In PagerFragment 's onResume() add this:
#Override
public void onResume() {
super.onResume();
for (Fragment fragment : getFragmentManager().getFragments()) {
if (fragment instanceof Tab1Fragment || fragment instanceof Tab2Fragment) {
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.detach(fragment);
ft.attach(fragment);
ft.commit();
}
}
}
Try to add this lines in your code:
public int getItemPosition(Object object) {
return POSITION_NONE;
}
and Add the below lines
pager.setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
... anything you may need to do to handle pager state ...
adapter.notifyDataSetChanged(); //this line will force all pages to be loaded fresh when changing between fragments
}
Under
pager.setAdapter(adapter);
Hope this may help you!
Ensure you pass the adapter instance the child fragment manager, not the fragment manager.
Like this:
this._adapter = new PagerAdapter(getChildFragmentManager());

Categories

Resources