Skip to main content
Version: 4.0

Custom Navigation

If you don't want to use the provided Mealz navigation, you can recreate the navigation yourself. We have documented a simple walkthrough, but feel free to implement your practice of Coordinators.

Steps

1. Create Standalone page

The first thing to be done is to create a FavoritesViewController or FavoritesView standalone page. The only parameters this page may expect are those related to navigating to the Catalog Feature. For example, you may want to pass a Navigation Delegate or a binding of the current tab.

The FavoritesParameters expects navigation functions & has optional viewOptions for customizing views.

Additionally, the last parameter is the gridConfig, which sets the number of columns, recipe dimensions, & spacing. It is an instance of CatalogRecipesListGridConfig.

FavoritesParameters

FavoritesParameters(
onNoResultsRedirect: { [weak self] in
// navigate to where your Catalog Feature implementation is, usually its own Tab
},
onShowRecipeDetails: { [weak self] recipeId in
guard let strongSelf = self else { return }
strongSelf.navigationController?.pushViewController(RecipeDetailsViewController(recipeId), animated: true)
}, onRecipeCallToActionTapped: { [weak self] recipeId in
guard let strongSelf = self else { return }
strongSelf.navigationController?.pushViewController(MyMealsViewController(), animated: true)
})

CatalogRecipesListGridConfig

CatalogRecipesListGridConfig(
numberOfColumns: 2,
spacing: CGSize(width: 6, height: 6),
recipeCardDimensions: CGSize(width: 300, height: 340),
recipeCardFillMaxWidth: true)

Putting it all together

Now we have all the parameters we need for the Favorites.

class FavoritesViewController: UIViewController {
var swiftUIView: Favorites<
FavoritesParameters> {
return Favorites.init(
params: FavoritesParameters(
onNoResultsRedirect: { [weak self] in
// navigate to Catalog Feature
},
onShowRecipeDetails: { [weak self] recipeId in
guard let strongSelf = self else { return }
strongSelf.navigationController?.pushViewController(RecipeDetailsViewController(recipeId), animated: true)
}, onRecipeCallToActionTapped: { [weak self] recipeId in
guard let strongSelf = self else { return }
strongSelf.navigationController?.pushViewController(MyMealsViewController(), animated: true)
}),
gridConfig: localRecipesListViewConfig
)
}
// The hosting controller for your SwiftUI view
private var hostingController: UIHostingController<Favorites<
FavoritesParameters>>?

override func viewDidLoad() {
super.viewDidLoad()
hostingController = UIHostingController(rootView: swiftUIView) // Initialize the hosting controller with your SwiftUI view
guard let hostingController = hostingController, let hcView = hostingController.view else { return }
hcView.translatesAutoresizingMaskIntoConstraints = false
addChild(hostingController)
view.addSubview(hcView)
NSLayoutConstraint.activate([ // you can also use SnapKit or other frameworks to set the bounds
hcView.topAnchor.constraint(equalTo: view.topAnchor),
hcView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
hcView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
hcView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
])
hostingController.didMove(toParent: self)
}
}

2. Add LikeButton to your components

Now, you'll need to add a LikeButton to your custom components. If you are only using MiamNeutral custom components, you can ignore this part. MiamNeutral already implements LikeButton on all of it's components.

LikeButton Component

The LikeButton component takes many parameters, but only one is mandatory, the recipeId. On all pages that have a LikeButton (RecipeCard, RecipeDetails, etc), this will be freely available.

To create a LikeButton, here is all you need to do:

LikeButton(
likeButtonInfo: LikeButtonInfo(recipeId: recipe.id)
)

LikeButtonInfo

Realistically, it is one line, but if you would like to customize the LikeButton, these are your options:

public struct LikeButtonInfo {
public let recipeId: String // id of the current Recipe
public let likedIcon: Image // Icon to pass if isLiked is true
public let unlikedIcon: Image // Icon to pass if isLiked is false
public let iconSize: CGSize // size of the icons
public let backgroundSize: CGSize // size of the entire button
public let backgroundColor: Color // color of the background
public let backgroundShape: AnyShape // Shape that the background is

Sample Customized LikeButton

Here's an (ugly) example of a custom LikeButton.

LikeButton(
likeButtonInfo: LikeButtonInfo(
recipeId: recipe.id,
likedIcon: Image.miamImage(icon: .caret),
unlikedIcon: Image.miamImage(icon: .cart),
iconSize: CGSize(width: 20, height: 20),
backgroundSize: CGSize(width: 25, height: 25),
backgroundColor: Color.red,
backgroundShape: AnyShape(Rectangle())
)
).padding(10)

Custom LikeButton