Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to do complex master-detail layout? #176

Open
ZakTaccardi opened this issue Dec 9, 2016 · 8 comments
Open

How to do complex master-detail layout? #176

ZakTaccardi opened this issue Dec 9, 2016 · 8 comments

Comments

@ZakTaccardi
Copy link

ZakTaccardi commented Dec 9, 2016

The example in the sample doesn't correctly survive configuration changes (you can get the portrait layout in landscape sometimes)

Example of layout I want to achieve

How should I be doing this? I've attempted to achieve this, but I am currently having issues restoring state.

I currently have the whole layout wrapped in a single HomeController, which has three childRouters via homeController.getChildRouter(view, TAG)

  • appBarRouter
  • navDrawerRouter
  • masterRouter (represents the current nav drawer selection)

masterRouter's root is masterControllerA (or masterControllerB when toggled by nav drawer). detailControllerA's is either:

  • pushed onto the masterRouter (in phone config, for single pane layout)
  • the root of the childRouter of its masterController (in tablet config, for two pane layout)

To avoid instantiating unnecessary controllers I'm always checking if the router/controller is already contained in the existing ViewGroup container/router by its tag.

Does any of this throw a red flag?

@ZakTaccardi
Copy link
Author

I've tried using a single dagger module with all routers/controllers in the same scope - but I hit this error when swapping nav drawer options (aka changing the root of the masterRouter

Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.util.List com.bluelinelabs.conductor.Controller.getChildRouters()' on a null object reference
    at com.bluelinelabs.conductor.ControllerHostedRouter.getSiblingRouters(ControllerHostedRouter.java:187)
    at com.bluelinelabs.conductor.Router.removeAllExceptVisibleAndUnowned(Router.java:711)
    at com.bluelinelabs.conductor.Router.setRoot(Router.java:283)

I'm guessing it has something to do with swapping setting the root of the masterRouter while reusing the childRouter instance of a controller that was previously attached (but no longer attached) to the masterRouter

@EricKuck
Copy link
Member

What's the problem with the way it's implemented in the demo app? The only time you can get the portrait layout in landscape is if you flip the phone when you're already in the detail view (I think). If there's another case I'm not aware of, please let me know.

Regarding your question, the only thing that throws a red flag is that it sounds like you're reusing potentially destroyed controllers. It all looks good besides that.

As for your crash, you're exactly right. If you try to use a Router that isn't attached to a host of any kind (ex: a child router whose controller isn't attached), you're not gonna have a good time.

@ZakTaccardi
Copy link
Author

The only time you can get the portrait layout in landscape is if you flip the phone when you're already in the detail view (I think)

Is this considered a bug? (I think it should be)

@EricKuck
Copy link
Member

Yeah, it probably should be considered a bug. I just wrote that as a quick demo without giving it too much thought. I've never had to use a master/detail view for much - how do apps typically handle this case? The master/detail example created by Android Studio's new project wizard seems to do what the demo does.

@ZakTaccardi
Copy link
Author

ZakTaccardi commented Dec 14, 2016

how do apps typically handle this case

  1. viewing DetailController in portrait
  2. user rotates device into landscape
  3. Expected: both MasterController and DetailController are visible, with the sameDetailController active that was visible in portrait

My confusion stems around how I should be restoring the state of routers and controllers in a configuration change when you switch from portrait to landscape (single pane layout to two pane layout).

I see two general approaches:

  1. Have a separate masterRouter and detailRouter for landscape. In portrait, there would only be one masterRouter, which the detailController would be pushed on to. The problem here is that the detailController will be in the masterRouter in portrait, but in the detailRouter in landscape).

  2. A single masterRouter, which masterController gets the detailRouter as its child router. I think this approach is the recommended one, but I struggled with it for the following reason.

The demo utilizes a single, static masterController - like a navigation drawer, it's always there. My use case has a dynamic masterController, where I need to swap out the masterController based on the nav drawer selection. If you have used Google Play Music before, my use case is more like that. Think of how that app toggles between the two navigation drawer options, Home and Music Library, when the HomeFragment and MusicLibraryFragment would be two of the masterControllers, that each have their own separate detailFragment

@tmtron
Copy link
Contributor

tmtron commented Jul 1, 2017

@ZakTaccardi did you ever find a good solution to this?

@tmtron
Copy link
Contributor

tmtron commented Jul 28, 2017

I think currently there is no easy way to handle this in Conductor.

The workaround that I came up with is this:

I have an OverviewController which always has 2 child-routers for

  • the MasterController (shows the list of items)
  • the DetailController (shows the selected item)

landscape-layout is easy: MasterController and DetailController are shown side-by side (e.g. in a horizontal LinearLayout)

prortrait-layout needs more work

  • I use a FrameLayout which will only show the MasterController or the DetailController
  • I must handle the transition: e.g. when you select an item in the list, slide the list out to the left and the datails in from the right
  • I must also handle the back-button: when you are in detail, transition back to the master
  • there may also be other things to consider: e.g. when the controllers have option menus, etc.

sdelaysam added a commit to sdelaysam/Conductor that referenced this issue Sep 6, 2019
@sdelaysam
Copy link

sdelaysam commented Sep 6, 2019

@EricKuck I guess the issue is still valid and I've added my implementation just in case.
#564

sdelaysam added a commit to sdelaysam/Conductor that referenced this issue Sep 10, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants