Open robcecil opened 6 years ago
As you mentioned, the current is experimental and may not make sense for most use cases. I have been thinking of some options and can poke around a bit to see what works. Applying a transform to the entire collection view may work, but I'm not sure if that's the best approach in terms of experience. I'll test out a few things and see if I can come up with a better solution.
I tried the transform route and it was unsatisfactory. I ended up scaling the grid:
It ended up being a little jittery, so I discretized the scaling, so I:
Employed a min/max strategy (0.75 ... 2.0) so not all scaling factors apply.
Employed an array of discrete zoom 'stops':
private var zoomStops: [CGFloat] = [0.75, 0.8, 0.85, 0.9, 0.95, 0.98, 1.0, 1.02, 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, 1.7, 1.75, 1.8, 1.85, 1.9, 1.95, 2.0]
When the user is using the gesture, I snap the current gesture.scale to one of these stops (closest fit).
I also added an "adorner" that simply is a UILabel that sits on top of the main content to indicate the current zoom amount. The adorner gets added during .begin and removed during .ended events on the gesture.
private lazy var zoomLabel: UILabel = {
let paddedLabel = PaddedLabel(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
paddedLabel.leftInset = 10
paddedLabel.rightInset = 10
paddedLabel.textAlignment = .center
paddedLabel.textColor = .white
paddedLabel.font = RobotoFont.medium(with: 16)
paddedLabel.layer.cornerRadius = 20
paddedLabel.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.7)
paddedLabel.layer.masksToBounds = true
return paddedLabel
}()
@objc func handlePinchGesture(pinchGesture: UIPinchGestureRecognizer) {
switch pinchGesture.state {
case .began:
view.layout(zoomLabel).center()
case .ended:
zoomLabel.removeFromSuperview()
case .changed:
var deltaScale = pinchGesture.scale
deltaScale = ((deltaScale - 1) * zoomSpeed) + 1
self.scale *= Float(deltaScale)
//self.scale *= Float(pinchGesture.scale)
let currentScale: Float = view.layer.value(forKeyPath: "transform.scale.x") as! Float
// BEGIN reset
pinchGesture.scale = 1.0
// END reset
self.scale = self.scale.clamped(lower: self.minScale / currentScale, upper: self.maxScale / currentScale)
//view.transform = CGAffineTransform(scaleX: CGFloat(self.scale), y: CGFloat(self.scale))
if let zoom = getZoom(forValue: CGFloat(self.scale)) {
print("zoom: \(self.scale) adjusted: \(zoom)")
self.zoomLabel.text = "Zoom: \(zoom * 100)%"
self.currentCellScale = zoom
}
// self.currentCellScale = CGFloat(self.scale).truncated(places: 1)
//case .ended:
//print("scale: \(scale)")
//self.currentCellScale = CGFloat(scale)
//view.transform = CGAffineTransform.identity
default: () // do nothing
}
}
You can see in the code, commented out lines where I attempted the transform.
I wonder why something like this wouldn't work better than reloadData():
COLLECTIONVIEW?.collectionViewLayout.invalidateLayout()
@nlampi ?
I temporarily added a func to expose the SwiftGridViewLayout:
public func invalidateLayout() { self.sgCollectionViewLayout.invalidateLayout() }
And tried using that rather than reloading the entire datasource.
I got gaps:
(I understand why the font sizes have not scaled - but I'm not sure why there are gaps)
Hi @robcecil, there is some caching done to increase the speed I believe updating the method mentioned to more closely match the below will work better for you. I am still in the process of investigating this as a built in feature that works easily as well as something that doesn't affect performance. Hopefully I'll have an update soon. Thanks for posting your approach!
open func invalidateLayout() { self.sgCollectionViewLayout.resetCachedParameters(false) self.sgCollectionViewLayout.invalidateLayout() }
The current pinch gesture is marked as experimental. It doesn't behave what I would expect for a grid-based, Excel-like presentation.
If you look at pinch on the apps:
They all zoom the content of the cells. It is almost like a transform is applied to the entire collection.
Any thoughts or ideas on how to modify SwiftGridView to emulate that? I've been poking around but nothing is really gelling except for the idea of attaching a transform on the entire collection view and scaling that via a pinch gesture.