christianselig,
@christianselig@mastodon.social avatar

SwiftUI question: I'm trying to make a slider that expands on touch. How do I make it so the progress part's height animates (instead of jumping), but the width stays instantly responsive (no animation)?

No matter where I put the .animation() modifiers I cannot seem to get it, haha

Gist: https://gist.github.com/christianselig/eda075422436f4e4934565da001455d4

Video of code with an interactive SwiftUI custom slider that jumps into place as soon as you start dragging, which looks weird. Code is available in linked GitHub Gist.

iKyle,
@iKyle@mastodon.social avatar

@christianselig idea for the future.

Make the inner progress always full height and then crop to the smaller height.

The width never animates.

The height animation is actually animating the crop instead.

Then 1 view animates. Then other view never animates?

christianselig,
@christianselig@mastodon.social avatar

@iKyle Then you get a capsule that when in the collapsed state is partially cut off

pixelscience,
@pixelscience@mastodon.social avatar

@christianselig I see in the gist comments my recommendation: use withAnimation

christianselig,
@christianselig@mastodon.social avatar

Good god, aheze over on the other site mentioned the very simple solution that if you just wrap the progress update in DispatchQueue.main.asyncAfter {} it fixes it. Huh

b3ll,
@b3ll@mastodon.social avatar
lightandshadow,
@lightandshadow@mastodon.social avatar

@christianselig Moving the capsules into a ZStack and placing the frame / animate modifiers on the stack seems to fix it without a call to dispatch. Added a clipShape to mask the slider deformation at the beginning. https://gist.github.com/christianselig/eda075422436f4e4934565da001455d4?permalink_comment_id=4894242#gistcomment-4894242

christianselig,
@christianselig@mastodon.social avatar

@lightandshadow Just hiding the deformation at the beginning is only awarding half points :p

stevengharris,
@stevengharris@mastodon.social avatar

@christianselig Might be overkill for you, but you can do this with SplitView (https://github.com/stevengharris/SplitView). I had to muck around a bit with insets and zorder because of Capsule, but looks pretty nice and seems responsive on height changes.

Code: struct DemoSlider: View { @State private var privateFraction: CGFloat = 0.5 var body: some View { let fractionHeight = 60 * privateFraction let height = min(50, max(10, fractionHeight)) let leadingInset = fractionHeight < height ? fractionHeight : height HSplit( left: { Capsule() .foregroundStyle(Color.green) .zIndex(1) }, right: { Capsule() .foregroundStyle(Color.black) .padding(EdgeInsets(top: 0, leading: -leadingInset, bottom: 0, trailing: 0)) .zIndex(0) .frame(height: height - 1) } ) .splitter { Splitter.invisible() } .onDrag { fraction in privateFraction = fraction } .frame(width: 400, height: height) } }

christianselig,
@christianselig@mastodon.social avatar

@stevengharris Oh wow, very cool! Yeah just not looking to introduce dependencies for this :(

dandylyons,
@dandylyons@iosdev.space avatar

@christianselig

One option is to drop to the Animatable protocol. Then the height and width could animate based off of different state.

https://swiftui-lab.com/swiftui-animations-part1/

christianselig,
@christianselig@mastodon.social avatar

@dandylyons Oh my!

lightandshadow,
@lightandshadow@mastodon.social avatar

@christianselig If I had to guess, the overlay is expanding instantaneously to give room for its parent to animate into its eventual destination height.

stroughtonsmith,
@stroughtonsmith@mastodon.social avatar

@christianselig just to be aware, if you roll your own volume slider you don't get system volume control or digital crown support, which is how the volume slider in e.g. Music works. It's why I'm stuck with crappy MPVolumeView

christianselig,
@christianselig@mastodon.social avatar

@stroughtonsmith Have you tried MPVolumeView on device? It feels super janky compared to system Sliders, I can't even get it to work reliably, so it sorta feels like a pick your poison situation

video/mp4

stroughtonsmith,
@stroughtonsmith@mastodon.social avatar

@christianselig it’s real picky about hit rect. I had to update Broadcasts like twice before launch just to make dragging work on device 😪

christianselig,
@christianselig@mastodon.social avatar

@stroughtonsmith Did you tweak it to make it more usable? I don't understand how it's so much trickier to interact with than just a normal Slider which I assumed it would be using behind the scenes. The status of the bar also doesn't seem to match 1:1 with the system volume level?

alexr,
@alexr@mastodon.online avatar
stroughtonsmith,
@stroughtonsmith@mastodon.social avatar

@alexr @christianselig I hadn't tried a wrapper, but that seems like a good idea

christianselig,
@christianselig@mastodon.social avatar

@stroughtonsmith @alexr Hahah, that's very clever. What's with the super small dispatch after?

auramagi,
@auramagi@hachyderm.io avatar

@alexr @christianselig @stroughtonsmith I also wrap MPVolumeView but with a couple of differences:

  • Having MPVolumeView in the view hierarchy disables the system popup when changing volume with buttons (which I want), so I put it in a hidden UIViewRepresentable. This way, you also don’t need the dispatch async call.
  • System volume changes in 0.05 increments, but the MPVolumeView slider is more granular, so I observe it instead of AVAudioSession.
christianselig,
@christianselig@mastodon.social avatar

@auramagi @alexr @stroughtonsmith Could you elaborate on the last point?

  • All
  • Subscribed
  • Moderated
  • Favorites
  • random
  • ngwrru68w68
  • rosin
  • GTA5RPClips
  • osvaldo12
  • love
  • Youngstown
  • slotface
  • khanakhh
  • everett
  • kavyap
  • mdbf
  • DreamBathrooms
  • thenastyranch
  • magazineikmin
  • anitta
  • InstantRegret
  • normalnudes
  • tacticalgear
  • cubers
  • ethstaker
  • modclub
  • cisconetworking
  • Durango
  • provamag3
  • tester
  • Leos
  • megavids
  • JUstTest
  • All magazines