My application has a menu within it that is divided into two panes when the screen is in landscape. Essentially it looks like below:
I also have a second layout, where the two fragments are separate, and clicking one item int he list opens the fragment of for the product that was clicked, like so:
The question is, what should happen when the user switches orientation? Going from portait to landscape is easy, but what about going the other way? If the user has clicked on a product (thus filling the right fragment) should they be taken back to left or right fragment on orientation change? There are spots in the app where the user can bypass the list and be taken directly to product; what happens if a user does that and changes orientation?
So my question is more best practices in design. Is there a standard best practice or rule of thumb for deciding which fragment stays on screen during an orientation change?
Related
I want to make an animation on click that a button slides down to the position of another button and at the same time I'm loading another activity. This other button is on the new activity. Picture it as if a button from one activity is replacing a button on another activity, so it has to slide down to where the new button is.
Can I measure this new button's position before the activity is loaded? So I can get the animation right for all screen sizes.
Activities are designed to be used as full-screen components, meaning that you understand that the other activity that pops in is going to take the full screen. If that is your goal, you can use shared element transitions with the activities to get the desired effect: https://developer.android.com/training/transitions/start-activity#start-transition
On the other hand, if you need both activities to stay on the screen, than you should rather to use fragments, as activities are not suited for that. For more info on that approach, see here: https://developer.android.com/guide/navigation/navigation-animate-transitions
I have a fragment, which consists of a viewPager in the top of the screen and two buttons at the bottom.
The buttons are for an additional navigation besides the swiping through the pages.
The viewPager consists of about 10 pages with some input fields.
However, when I swipe through the pages and rotate my phone to landscape, the viewPager automatically changes the current item and selects the first page again. Another effect is, that all input data to this point are cleared.
This is really annoying because you have to start all over again.
Is it possible to switch between landscape and portrait mode without this issues?
Some background information:
the app consists of one activity, which is filled with different fragments
a navigation drawer is implemented to choose which fragment will be shown
When you change orientation you are essentially refreshing your activity losing your data such as current page, fragment etc, you need to save your data across the states, i would suggest looking into savedInstanceState.
I have an Activity with two Fragments, where only one Fragment is shown at the same time. But the user can swipe between them.
The left Fragment is a MapFragment, and the user is able to scroll and zoom this as normal. But when the user starts a swipe touching the rightmost part of the screen, it will scroll to the other Fragment instead of scrolling the map.
In other words:
if (motionEvent.getX()<myFragment.getWidth()-SOME_VALUE) {
scroll the map
} else {
switch to the other Fragment
}
My question: What is a good value for the constant SOME_VALUE? Are there any system defined constants I can use?
Wild guess: SOME_VALUE should be a percentage of your screenwidth, for example 10%.
Most important is to test this on an actual device. I'm not sure if the user finds your described behaviour logical (I think I wouldn't).
I myself would probably choose a small menu bar at the top of the screen to be able to switch between the fragments. Then your swipe has become very simple without having to choose what to do depending on the position that started the swipe.
I am trying to create a layout in an activity that will look different in landscape and portrait, however it will contain the same sections, just in different places on the screen.
Most examples I find on fragments is always the list and detail, which is not what I'm looking at.
In my example I have, amongst others,
a scrolling image section (carousel)
a page title with some brief details
a carousel of thumbnails
two buttons
full details of the page
Now in the landscape layout, the image section will always be on the left side with down the right side, the page title, carousel of thumbs, two buttons and full details.
In the Portrait the title will appear at top, with image carousel beneath, then thumbs, then buttons etc.
The way it works in my head, is that each section should be a fragment, and then depending on the layout file in the respective res/layout folder corresponding to land/port, the fragments are arranged accordingly. But I'm also thinking is each section a whole fragment? Or could it be a separate view that get's loaded in, but just in a different order depending on the screen orientation.
I hope that made sense?
Does anyone have any good tutorials that explain exactly when you should and shouldn't use fragments. All the usual suspects just list the list/detail example, which is not applicable in my case.
tl;dr Can I use fragments as modules/blocks in various layouts or should I just create other layouts and display them inside the main layouts.
Fragments can be used to have split screen and to store previous state unlike views. It is difficult to manage back button with views
If you just want to change how the screen is laid out, the answer is neither. You can define orientation-specific resources (either a separate layout file for each orientation or different dimensions/constraints for each orientation) and the system will just provide you with the correct resource set for the current orientation.
That said, it sounds like you may be describing a modified version of master/detail flow. If this is the case, fragments are a good way to go since the landscape view is actually several separate screens in the portrait version of the app, so each section needs it's own state and lifecycle, which fragments provide.
Now, I know you said you wanted an example beyond a list and detail view, so here's some more details on when to use fragments:
Fragment, like activities, have state and lifecycle. Custom views do not have lifecycle and are completely dependent on the activity or fragment containing them.
You might use a custom view when you have a widget on screen that is used in multiple places and is just like any other view – bound to the activity when the layout is inflated and controlled from there. It's a way to either reduce duplicating combinations of views in your layout or to draw a custom view that doesn't exist yet.
Fragments are good when you need some state or lifecycle for a section of the app that might get used in multiple places or shouldn't be logically connected to the activity it is contained in. If you use the new Navigation Component, you actually just define one activity and then each screen in the navigation tree is a fragment that gets swapped out as the user navigates around the app. Here each child component on the screen (each "screen" that the user navigates to) has it's own lifecycle, business logic, etc, so mixing the code for all of that in the activity wouldn't make sense.
So the question comes down to what you are trying to build, and this may be a case where the best way to learn the difference is to try each option out as bit. The differences become more clear with practice using them. As a general rule of thumb, personally, I only really use custom views when I am trying to make a new view that doesn't exist elsewhere. If what I'm trying to do is simply a matter of laying out existing views in a new way, the answer is probably some trick in the layout file or layout code inside the activity. If I'm trying to make a stand-alone piece of the app that does stuff, especially if it also appears in multiple places in the app, I'll probably be building a fragment.
I'm having trouble wrapping my head around how to properly manage Fragments in a typical list-detail design pattern.
My layout is working fine and is structured like this for the landscape view (dual pane):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout ... >
<FrameLayout android:id="#+id/list" ... />
<FrameLayout android:id="#+id/container" ... />
</LinearLayout>
And like this for the portrait view (single pane):
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout android:id="#+id/container" ... />
I also have a refs.xml in res/values-w600dp/ to make sure the appropriate layout is loaded based on the screen width of the device.
When a list item is selected, the landscape view should show the list and the details side-by-side, while the portrait view should show only the details fullscreen. When nothing has been selected, the landscape view should show the left on the left and blank space on the right, while the portrait view should show only the list fullscreen.
However, here's where I'm having trouble:
Do I use a "main" Activity for the list + optional details layout, and another "details" Activity for the portrait, details-only layout? This seems to be what the Fragments guide example does. I've gotten this approah to work generally, but how do I maintain the state of my details fragment when the orientation changes?
Consider the opposite case shown above -- rotating from portrait to landscape while the details are visible means the details Activity would need to be finish()ed so the main Activity could display the two-pane layout, but this also destroys the details fragment and its savedInstanceState. If the user has typed information into the EditText fields in the details fragment, then rotates the device, how do I preserve the entire UI state of the details fragment when I add it to the main (two-pane) Activity?
Do I use only one Activity and manage the Fragments myself? This allows me to retain the state of the details UI when the orientation changes (because Android takes care of this automatically), but it gets messy when it comes to the back stack.
Consider the case in the image -- rotating from landscape to portrait when the details are visible should show show the details single-pane, but how do I properly manage the back stack and ActionBar home icon to show the list single-pane? Rotating back to landscape would also need to undo whatever back stack manipulation I did previously, as both fragments will be visible at once.
After some more searching, I found two similar questions (Switch from dual pane to single pane on orientation change maintaining fragment stack and Retain Fragment state between Activities), but my situation is slightly different because I'm not trying to retrofit this functionality but best plan for it up front. What am I missing? Surely Android can manage both the back stack (as in the multiple Activity case) and the UI state (as in the single Activity case) at once, right?
I solved this by going the multiple activities route. See my answer to "Retain Fragment state between Activities".
The key was using FragmentManager.saveFragmentInstanceState() to save the state of the fragment's UI and Fragment.setInitialSavedState() to restore it when instantiating the same fragment in another activity.
For my purposes, I found that I needed to save the UI state in two cases. I created a helper method public void saveState() inside my fragment and call this from the fragment's own onPause() method as well as from my "main" activity immediately prior to using replace() to attach a new instance of the fragment to the dual-pane layout.
I'm still interested in know if the back stack manipulation required for this type of single/dual-pane layout scenario is possible or if the single activity approach would require overriding onBackPressed and simulating a back stack manually.
It is possible to use only one Activity, but you'll have to manage the backstack when in portrait orientation yourself.
As you describe the behaviour of the app, there could be 4 states:
State A: portrait, showing the list fragment.
State B: portrait, showing the details fragment with the list fragment on the back stack.
State C: landscape, showing the list fragment on the left and a blank space on the right.
State D: landscape, showing both the list fragment and the details fragment side by side.
Imagine you are on state D (with both fragments, let's call them FA and FB), and you change the orientation of the phone. The following state should be the state B, but the problem is that your portrait layout only has one FrameLayout. Using the following as the single pane layout:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout android:id="#+id/list" ... />
Android will recreate FA and will have it attached to that FrameLayout. FB, on the other hand, will also be recreated but will not have a container associated, so it won't show up. At this point you could create another fragment, FB2 with the same contents as FB, and use it to replace FA. You will have FA-FB2 in your backstack and FB hidden.
If you change the orientation again (expecting the state D), you can use onSaveInstanceState() to pop FB2 from the backstack with popBackStack(), thus having again FA and FB. Before removing FB2, you may also want to copy its content to FB. When the app is again in state D, FB will have its FrameLayout.
There would be a few other transitions and situations that you would have to take care of, but the main idea would be that.
It's not a very elegant solution, so I am sure that it has to be a better, maybe more efficient (without replicating Fragments for example) way to solve this problem.