I have a two problems and struggle for a few days. I am not sure what the right way is.
I want to combine a tab layout with a view pager containing three fragments (the tab layout and the view pager are the home screen) and a navigation drawer.
And I think that everything you can navigate to from the drawer should be a fragment accept settings or something similar.
So should I let the tab layout in the layout of the main activities layout or should I put the this layout also in a fragment (so view pager with fragments inside a so calling home fragment)?
When starting the app I check if the user is logged in and if he is download data from Firebase. I do this in another fragment (data fragment) there I setretaininstance to true.
So currently one of the tab fragments needs the data from Firebase but soon all of them will need it.
How do I pass the data (Lists) from the data fragment to the tab fragments or the so called home fragment and then to the tabs.
I already tried interfaces but I don't know how to handle confirmation changes.
Considering the two problems or the combination of both how would you solve this / which design approach is better only use fragments or let the home screen inside the main activity and change the view when the user navigates from the drawer to fragment?
PS. I will add some code as soon as possible.
Thanks.
TabLayout and the ViewPager should be in the Activity layout since it makes more sense, as the Activity manages the Fragments. Also, navigation drawer should navigates through Activities, and Activities between Fragments. Again, that's the logical thing for a decent code organization, and it prevents repetitions in layout (AKA more than one button to navigate to the same fragment).
For the Firebase issue, I suggest you start the call in the Activity, and then call a function in all fragments with the retrieved information. Something like this:
new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(MyFragment f : mFragmentList)
f.addData(dataSnapshot);
}
}
If you really want the Fragment to make the call to Firebase, then you can create you own Event and Listener set.
public class SnapshotRetrievedEvent {
private static List<SnapshotRetrievedListener> listeners = new ArrayList<>();
public static void addListener(SnapshotRetrievedListener listener){
listeners.add(listener);
}
public static void notify(DataSnapshot snapshot) {
for(SnapshotRetrievedListener listener : listeners)
listener.onSnapshotRetrived( snapshot );
}
}
public interface SnapshotRetrievedListene {
void onSnapshotRetrieved(DataSnapshot snapshot);
}
Then in your Fragment waiting for the snapshot, you add the listener like this:
SnapshotRetrievedEvent.addListener(
new SnapshotRetrievedListener(){
#Override
public void onSnapshotRetrieved(DataSnapshot snapshot){
// Do stuff
}
}
);
onSnapshotRetrieved will be called when you call SnapshotRetrievedEvent.notify(snapshot) in your other Fragment.
Hope this helps
Related
I'm newbie with MvvmCross. I'm developing an app using Mvx v6.0.1.
I want to make a kind of stepper using fragments (specifically 4 fragments or 4 steps), all of these fragments are embedded into an main activity. The main activity layout has a button, when I tap these button fragment is switched to the next step. I have created one viewmodel for each fragment and one more for the main activity. The problem I have is that I need to get some values from each step and pass to the next step.
I'm trying to share only one viewmodel for every view (fragments and activity). Is there any way to achieve this?
If yes, How can I distinguish each steps/fragments for navigate across them?
I was trying to set same viewmodel to Activity and fragment:
//Activity code
public class AttendanceActivity : BaseActivity<AttendanceViewModel>
{
protected override int ActivityLayoutId => Resource.Layout.activity_attendance;
//some logic
}
//Fragment code
[MvxFragmentPresentation(ActivityHostViewModelType = typeof(AttendanceViewModel),
FragmentContentId = Resource.Id.attendance_content_frame,
AddToBackStack = true)]
public class AttendanceFragmentSetpOne : BaseFragment<AttendanceViewModel>, IOnClickListener
{
protected override int FragmentLayoutId => Resource.Layout.fragment_attendance_step_one;
//Some logic
}
But when I make this, the app never pass from splash screen.
I hope explain myself and somebody help me with this "problem".
Thanks in advance.
I made an activity which is simply a viewpager with a few tabs. Each tab is like a form that the user needs to fill out. When the user is done, the data from the view pager should be collected and sent back as a result. I almost have this working but for some reason the data on my first tab seems to get reset when the user gets to the third tab. I'm guessing this is due to some view recycling in the pager. Anyways, I'm wondering if there is some easy way to gather all the data from the different tabs or do I have to create some kind of tight coupling between the activity and viewpager object?
you have to use SmartFragmentStatePagerAdapter as described here "https://guides.codepath.com/android/ViewPager-with-FragmentPagerAdapter" and than need to
vpPager.setOffscreenPageLimit(3);
Your issue should be resolved. :)
A viewpager will kill off the fragment if it is 2 pages away from the current page. It then recreates it when the pager is on a page that is 1 step away from it.
You should move your form data into your activity/fragment that is holding the viewpager and use fragment listeners to update your data accordingly
For example, you could use a fragment listener like below to pass the data to/from the containing activity
public interface MyFragmentListener{
void saveMyFormData(MyFormData formData);
MyFormData getFormData();
}
private MyFragmentListener mListener;
//initialise fragment listener in onAttach (or elsewhere)
private void initFormView(){
MyFormData data = mListener.getFormData();
//do stuff with data
}
private void saveData(){
mListener.saveMyFormData(myFormDataObject);
}
I'm aware the View structure for Android is completely different (ie. Activities instead of View Controllers) but I need to create a Navigation Bar that persists between views.
Is the best way really to have just one single Activity and then a lot of Fragments?
If so, has this implementation already been done somewhere else that I can use? It seems like something that would come up a lot as I've seen numerous Android apps do this.
I made a Framework (github) to provide a hierarchical navigation pattern, with animations to provide sense of navigation, rather than launching new Activities every time.
Here's how to use it:
Add the framework to your project as a Module
Add a new Java class in your project ("File - New - Java Class").
Note: If you are editing the Activity.java file that provides you the template, delete all its implementations and leave it empty.
Make it extend NavigationActivity
Implement all the NavigationActivity abstract methods
(in Android Studio if you click Alt + insert and select implement - methods all the function definitions are automatically generated).
public class NavigationTest extends NavigationActivity{
#Override
public Fragment firstFragment() {
//return the first fragment that will be shown
}
#Override
public Boolean showBackButtonInFirstFragment() {
//show back button already in the first Fragment
//set to True if this activity is called by another Activity
//the back button will then pop back to the previous Activity
}
#Override
public Boolean showMasterDetailLayoutInTablets() {
//set to false if you don't want a master-detail layout in tablets
}
}
Presenting a new Fragment
You can present a new fragment (with a nice animation) by calling the pushFragment method from NavigationActivity.
public void pushFragment(Fragment newFragment, animationType animation, boolean showAsDetailFragmentIfPossible)
newFragment (Fragment): New Fragment that will be presented
animation (animationType): Animation type enum: RIGHT_TO_LEFT, BOTTOM_TO_TOP, FLIP
showAsDetailFragmentIfPossible (boolean): If set as True, the user is in a Tablet, and you are using a master-detail layout, the Fragment will be shown in the detail Fragment (the panel in the right)!
Since you can access the activity from any Fragment with the getActivity() method, you can show a new Fragment from the currently displaying Fragment.
For example you can put this code within a button click listener:
NextFragment f = new NextFragment();
NavigationActivity nav =((NavigationActivity)getActivity());
nav.pushFragment(f,NavigationActivity.animationType.RIGHT_TO_LEFT,false);
You don't have to worry about implementing the back button behaviour. This is handled automatically by the NavigationActivity class.
I am creating a tabbed application using a FragmentPagerAdapter and android.support.v4.view.ViewPager. In order to follow best practices and separation of concerns I have separated my app into several different fragments. Each of the fragments has an interaction listener that requires an Activity to subscribe to. Since I only have one activity in the entire app do I have to make the parent (tabbed navigation) activity implement all the listeners in the entire app? This seems like it would be bad practice and create one large monolithic Activity class that controls the flow of everything.
I have three fragments inside of another fragment that I use as a home page tab. The home page fragment implements the interfaces of the three sub fragments. The problem is that the home page fragment is not an Activity so the sub fragments throw an exception on onAttach.
What am I missing? How can I implement fragment listeners in a tabbed application without making one large and messy Activity class
After researching further with different keywords I found a good answer here: https://stackoverflow.com/a/23144683/2435006
They key was to make an onAttachFragment(Fragment f) method rather than using the onAttach(Activity a) and calling it in the onCreate method.
Here is the example from the answer above:
public void onAttachFragment(Fragment fragment)
{
try
{
mListener = (OnInteractionListener) fragment;
} catch (ClassCastException e)
{
throw new ClassCastException(fragment.toString() + " must implement OnInteractionListener");
}
}
#Override
public void onCreate(Bundle savedInstanceState)
{
Log.i(TAG, "onCreate");
super.onCreate(savedInstanceState);
this.mContext = getActivity().getApplicationContext();
onAttachFragment(getParentFragment());
....
}
I think you need a good sample related to Fragments. Here is a sample with detailed explanations # ViewPager with FragmentPagerAdapter. The listeners are at onCreateView method at the Fragment. You don't want to set a bunch of listeners in the Activity.
I am using ViewPager in my app. In each fragment there is a toolbar. On a single tap on the image the the toolbar is animated to the top out of the screen. But I have to notify all the remaining fragments to do the same thing. So that when the user scrolls to the next fragment he doesn't see the toolbar.
I tried adding setUserVisibleHint(), but it did not work as it was called only when the fragment was completely visible, thus showing the toolbar exiting to the user.
Then I tried it in onResume and setting pager.offscreenpagelimit=1, it worked fine for the fragment next to next but did not work for the next fragment.
Thanks!!
First Notify your activity from fragment using:
In Fragment on Animation End:
((YourActivity)getActivity()).hideToolbar();
In Activity:
public void hideToolbar() {
// Redraw view pager without toolbar (notify your adapter create pager without toolbar)
}
Well, why don't you get your toolbar out of your fragments and just create one in activity and change its state on page change (definitely it will not slide but may
You have 2 problems to face.
How to call existing fragments to hide/show their toolbars.
How to create another fragments with hidden toolbar.
First problem can be easly done by using Otto event library found here. Just paste this code in your viewpager fragments:
Bus bus = new Bus();
#Override
protected void onResume() {
super.onResume();
bus.register(this);
}
#Override
protected void onPause() {
super.onPause();
bus.unregister(this);
}
#Subscribe
public void onToolbarEvent(ToolbarEvent event) {
//do your toolbar logic
}
Then in your onClick event on image just put (of course creating bus object before)
bus.post(new ToolbarEvent());
ToolbarEvent can be just empty class. If you read about Otto events you will understand how it works.
Another problem is how to know that the toolbar should be hidden/shown, when viewpager instantiates new fragments? Simply add a boolean flag in your shared prefferences, so every time fragment is created, it can check if it can show toolbar or not e.g. in onViewCreated() method. The example how to use shared prefferences can be found here
Hope I helped a little bit.