Skip to content

[MBL-3054] Fix liquid glass styling of disabled nav bar buttons#2782

Merged
ifosli merged 7 commits into
mainfrom
ifosli/liquidGlassNavBarButtons
Mar 6, 2026
Merged

[MBL-3054] Fix liquid glass styling of disabled nav bar buttons#2782
ifosli merged 7 commits into
mainfrom
ifosli/liquidGlassNavBarButtons

Conversation

@ifosli

@ifosli ifosli commented Mar 5, 2026

Copy link
Copy Markdown
Contributor

📲 What

Remove the liquid glass styling from the container nav bar views and add it directly to the contained button. This makes the liquid glass effect respect when the button is in a disabled state.

I've tried to keep the iOS 18 styling mostly the same, but I had to get rid of the loading bar button storyboard to get the glass effect to behave nicely, so I'm including before/after comparisons of both iOS 18 and iOS 26.

👀 See

Jira

Before 🐛 After 🦋
Simulator Screen Recording - iPhone 17 - 2026-03-05 at 11 21 12 Simulator Screen Recording - iPhone 17 - 2026-03-05 at 11 16 15
Simulator Screen Recording - iPhone 16 Pro Max - 2026-03-05 at 11 19 44 Simulator Screen Recording - iPhone 16 Pro Max - 2026-03-05 at 11 15 05
Simulator Screen Recording - iPhone 17 - 2026-03-05 at 10 27 49 Simulator Screen Recording - iPhone 17 - 2026-03-05 at 11 16 36
Simulator Screen Recording - iPhone 16 Pro Max - 2026-03-05 at 10 25 48 Simulator Screen Recording - iPhone 16 Pro Max - 2026-03-05 at 11 15 33

✅ Acceptance criteria

  • Disabled button feels disabled (no tap animation)
  • Styling is consistent

Todo

  • I'm going to put up a separate PR that deletes the ChangeEmailViewController - this is no longer in use after we built a swiftUI version.

@ifosli ifosli self-assigned this Mar 5, 2026
@ifosli ifosli marked this pull request as ready for review March 5, 2026 18:22
.onReceive(self.reactiveViewModel.resetEditableText) { newValue in
self.showLoading = !newValue
}
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This block of code is just copy-pasted from the main view builder above. The only change is in the lines below

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a nice little bit of cleanup!

|> UIButton.lens.titleLabel.font .~ UIFont.ksr_body()
|> UIButton.lens.titleColor(for: .normal) .~ LegacyColors.ksr_create_700.uiColor()
|> UIButton.lens.titleColor(for: .disabled) .~ LegacyColors.ksr_support_300.uiColor()

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I first tried to keep the styling in this method and add the glass effect here. Interestingly enough, bindStyles gets called enough times/at weird times that setting the button configuration here causes the title to disappear 🤷 so now this styling code gets called only once, during set up.

@ifosli ifosli requested review from a team and amy-at-kickstarter and removed request for a team March 5, 2026 18:28

@amy-at-kickstarter amy-at-kickstarter left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These changes LGTM. I have a couple non-blocking suggestions for making these changes a little more self-documenting, and adding a little extra testing.

.onReceive(self.reactiveViewModel.resetEditableText) { newValue in
self.showLoading = !newValue
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a nice little bit of cleanup!

@@ -35,6 +35,9 @@ final class ChangePasswordViewController: UIViewController, MessageBannerViewCon
self.saveButtonView.addTarget(self, action: #selector(self.saveButtonTapped(_:)))

let navigationBarButton = UIBarButtonItem(customView: self.saveButtonView)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a pragmatic reason we have all of these UIButtons wrapped in UIBarButtonItems? Could we implement the same loading spinner behavior in a plain UIBarButtonItem?

Cleaning that up seems out-of-scope for this fix, but I think it might be worth throwing in a little explanation in the code - just so we know why we had to do this, and so we can clean it up if we need to.

I'd suggest something like adding a well-documented exetension, like

extension UIBarButtonItem {
   //We have to do this because ...
   convenience init(button: UIButton) {
      self.init(customView: button)
      if #available(iOS 26.0, *) {
         navigationBarButton.hidesSharedBackground = true
       }
   }
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, that's a good idea. I added this as a static helper function to the LoadingBarButtonItemView instead, because I think that's the most relevant context for explaining what's going on here.

Getting rid of the UIButton entirely is an interesting idea. I do think that would get us a slightly more polished result (the frame height of the liquid glass effect looks like it's slightly shorter when the effect is applied to the button directly). I do think implementing the loading state could get a bit complicated, since we don't want users to be able to tap the button when the loading indicator is showing, but I also don't think we want the loading indicator to look grayed out. I'm going to stick with the UIButton for now, but I think we should explore this idea if we do need to make more changes here.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉

@@ -3,34 +3,61 @@ import Library
import Prelude

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is LoadingBarButtonItemView covered in any meaningful screenshot test? Would it be a huge pain to give it its own screenshot test? Just thinking it would be nice to verify there were no regressions with deleting the nib file.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call! I've added snapshot tests. I did mess with the commit history so I could add the snapshot tests before making changes to the view itself.

@ifosli ifosli force-pushed the ifosli/liquidGlassNavBarButtons branch from 9e481fb to 0880c1d Compare March 5, 2026 22:12
loadingBarButtonItemView.setTitle(title: "Button")
loadingBarButtonItemView.setIsEnabled(isEnabled: false)

assertSnapshot(of: loadingBarButtonItemView, as: .image)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I considered using our test helpers instead, but they do not respect intrinsic content size width, so I went with this approach instead. I'm only testing this in light mode because a) this view is old enough that it has not been designed/optimized for dark mode and b) because the background is transparent, dark mode tests look off.

@ifosli ifosli merged commit 91650f6 into main Mar 6, 2026
7 checks passed
@ifosli ifosli deleted the ifosli/liquidGlassNavBarButtons branch March 6, 2026 00:21
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

Successfully merging this pull request may close these issues.

2 participants