apptekstudios / ASCollectionView

A SwiftUI collection view with support for custom layouts, preloading, and more.
MIT License
1.35k stars 161 forks source link

Manually position / add padding to ActivityIndicator #189

Open codetheweb opened 3 years ago

codetheweb commented 3 years ago

First of all, thank you for such a high quality open source library - I wouldn't have been able to make my app without it.

I'm wondering if there's a way to manually position or add padding to the UIActivityIndicator view that appears on scroll-to-refresh. I would like it to be positioned below the buttons, instead of overlapping with them (the floating buttons fade out once the user starts scrolling downwards, and the scrollview fills the entire window). I'm relatively new to Swift / iOS development, so I might just be missing something trivial.

See this screenshot for what I mean:

IMG_5058D4642AE7-1

timothycosta commented 3 years ago

I would also like to see this. I was able to get a reference to the underlying scroll view and modify the refresh control's bounds directly using a GeometryReaderProxy.frame(in: .global) in the background of my header content. But it's not too clean.

codetheweb commented 3 years ago

@timothycosta could you share some code showing how you accomplished that?

timothycosta commented 3 years ago

@codetheweb Basically, I keep track of the underlying UIScrollView in @State. You can get that by using a library like Introspect.

Then, I use something like:


MyCollectionView().overlay(alignment: .top) {
  self.header // Stay out of this thing's way
      .readGeometry { proxy in // Shortcut for GeometryReader + code execution block.  Gets the size.
        let frame = proxy.frame(in: .global)
        self.scrollView?.verticalScrollIndicatorInsets.top = frame.maxY
        self.scrollView?.refreshControl?.bounds.origin.y = -frame.maxY
      }
    }
codetheweb commented 3 years ago

Thanks for pointing me in the right direction.

I ended up implementing this function in a custom layout delegate (since I was using one already):

func collectionView(_ collectionView: UICollectionView, targetContentOffsetForProposedContentOffset proposedContentOffset: CGPoint) -> CGPoint {
  self.collectionView.wrappedValue = collectionView

  return proposedContentOffset
}

where

class WaterfallScreenLayoutDelegate: ASCollectionViewDelegate, ASWaterfallLayoutDelegate {
    ...
    public var collectionView: Binding<UICollectionView?> = .constant(nil)
    ...
}

and the modifier on the collection view:

.customDelegate({
  let delegate = WaterfallScreenLayoutDelegate.init()
  delegate.collectionView = self.$collectionView
  return delegate
})
apptekstudios commented 3 years ago

Sorry for the delayed response, I've had a long break and am back at last. This seems like something I could build into the library...

Potentially just a modifier that defines an offset amount for the activity indicator? Did adjusting the origin achieve what you wanted?

codetheweb commented 3 years ago

Adjusting the origin worked fine for me.

It definitely feels hacky, so a library feature would be great but it works fine for now.