如何限制 UIScrollView 仅垂直缩放?

发布于 2024-12-12 09:57:00 字数 427 浏览 0 评论 0原文

我有一个 UIScrollView,用来表示图表上的轴。我希望用户能够使用通常的捏合动作放大轴,但它只能在垂直方向上缩放,而不是水平方向上缩放。

我的问题类似于这个,但我已经尝试了那里建议的解决方案(覆盖子视图的 SetTransform 方法,以便它忽略一个方向的缩放),并且在限制水平缩放而不是垂直缩放时它可以完美地工作。当我尝试垂直实现它时,第一次捏合动作效果很好,但随后的捏合似乎在产生任何效果之前将缩放比例重置为 1。

有谁知道可能导致这种行为的原因,更重要的是我如何解决它?

我正在使用 MonoTouch,但使用 Objective-C 的答案很好。

I have a UIScrollView which I'm using to represent an axis on a graph. I'd like the user to be able to zoom in on the axis using the usual pinch motion, but for it to only scale in the vertical direction, not horizontally.

My question is similar to this one, but I've tried the solution suggested there (overriding the subview's SetTransform method so that it ignores scaling in one direction) and it works perfectly when constraining scaling horizontally, but not vertically. When I try implementing it vertically the first pinch action works fine, but subsequent pinches seem to reset the zoom scale to one before having any effect.

Does anyone know what might be causing this behaviour, and more importantly how I can get around it?

I'm using MonoTouch but answers using Objective-C are fine.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

凑诗 2024-12-19 09:57:01

我知道这个问题是很久以前发布的,但这里有一个针对任何陷入这个问题的人的答案。

我查看了您链接到的问题,rankAmateur,我认为修复在那里找到的解决方案以满足您的需求的简单方法是在 setTransform: 方法中用其“d”属性替换 CGAffineTransform 的“a”属性。

- (void)setTransform:(CGAffineTransform)newValue;
{
 CGAffineTransform constrainedTransform = CGAffineTransformIdentity;
 // constrainedTransform.a = newValue.a;
 constrainedTransform.d = newValue.d;
 [super setTransform:constrainedTransform];
}

我不太熟悉 CGAffineTransorm,但这对我有用,在浏览文档后,似乎“a”属性对应于视图的 x 轴,“d”属性对应于视图的 y 轴。

编辑

因此,在回去并意识到问题的真正含义之后,我做了一些更多的研究,我有点困惑,但是经历了上面提到的RankAmateur相同的行为,这似乎非常不寻常当缩放仅限于水平方向时,CGAffineTransform 可以与 ZoomScale 完美配合,但当缩放仅限于垂直方向时则不能。

我能提供的唯一假设是,它可能与 Core Graphics 和 UIKit 不同的默认坐标系有关,因为在这些坐标系中,x 轴以相同的方式起作用,而 y 轴以相反的方式起作用。也许不知何故,这在前面提到的 setTransform 重写中变得混乱。

I know this question was posted quite a while ago, but here's an answer for anyone stuck on this problem.

I looked over the question you linked to, rankAmateur, and I think the simple way to fix the solution found there to suit your needs is to replace the CGAffineTransform's "a" property with its "d" property in the setTransform: method.

- (void)setTransform:(CGAffineTransform)newValue;
{
 CGAffineTransform constrainedTransform = CGAffineTransformIdentity;
 // constrainedTransform.a = newValue.a;
 constrainedTransform.d = newValue.d;
 [super setTransform:constrainedTransform];
}

I'm not very well versed in CGAffineTransorm, but this worked for me and after browsing the documentation it seems the "a" property corresponds to a view's x-axis and the "d" property corresponds to a view's y-axis.

EDIT

So after going back and realizing what the question really was, I did some more digging into this and I'm a bit stumped, but having experienced the same behavior that rankAmateur mentions above, it seems incredibly unusual for the CGAffineTransform to work perfectly well with zoomScale when zooming is constrained to only horizontally, but not when constrained to only vertically.

The only hypothesis I can offer, is that it might have something to do with the differing default coordinate systems of Core Graphics and UIKit, since in those coordinate systems the x-axis functions in the same way, while the y-axis functions oppositely. Perhaps somehow this gets muddled up in the previously mentioned overriding of setTransform.

忆梦 2024-12-19 09:57:01

这个答案在很大程度上取决于starryVere的答案(竖起大拇指!)

这是starryVere的Swift代码。它位于缩放的 UIView 子类中:

var initialScale: CGFloat = 1.0
override var transform: CGAffineTransform {
    set{
        //print("1 transform... \(newValue), frame=\(self.frame), bounds=\(self.bounds)")
        var constrainedTransform = CGAffineTransformIdentity
        constrainedTransform.d = self.initialScale * newValue.d // vertical zoom
        //constrainedTransform.a = newValue.a // horizontal zoom
        super.transform = constrainedTransform
        //print("2 transform... \(constrainedTransform), frame=\(self.frame), bounds=\(self.bounds)")
    }
    get{
        return super.transform
    }
}

注释掉的打印对于理解转换过程中边界和框架发生的情况非常有帮助。

现在到比例问题:

包含 UIScrollViewDelegate 的方法 rollViewDidEndZooming 有一个参数比例。根据我的测试,这个参数scale包含值zoomedView.transform.a,它是我们使用CGAffineTransformIdentity设置为1.0的水平比例因子。所以比例始终为 1.0。

解决方法很简单:

func scrollViewDidEndZooming(scrollView: UIScrollView, withView view: UIView?, atScale scale: CGFloat) {
    let myScale = zoomView.transform.d

}

使用 myScale 就像在水平缩放的情况下使用 scale 一样。

This answer depends heavily on the answer from starryVere (thumbs up!)

this is starryVere's code in Swift. It is in the zoomed UIView subclass:

var initialScale: CGFloat = 1.0
override var transform: CGAffineTransform {
    set{
        //print("1 transform... \(newValue), frame=\(self.frame), bounds=\(self.bounds)")
        var constrainedTransform = CGAffineTransformIdentity
        constrainedTransform.d = self.initialScale * newValue.d // vertical zoom
        //constrainedTransform.a = newValue.a // horizontal zoom
        super.transform = constrainedTransform
        //print("2 transform... \(constrainedTransform), frame=\(self.frame), bounds=\(self.bounds)")
    }
    get{
        return super.transform
    }
}

The commented out prints are very helpful to understand what happens with bounds and frame during the transformation.

Now to the scale problem:

the method scrollViewDidEndZooming of the containing UIScrollViewDelegate has a parameter scale. According to my tests this parameter scale contains the value zoomedView.transform.a which is the horizontal scale factor that we set to 1.0 using CGAffineTransformIdentity. So scale is always 1.0.

The fix is easy:

func scrollViewDidEndZooming(scrollView: UIScrollView, withView view: UIView?, atScale scale: CGFloat) {
    let myScale = zoomView.transform.d

}

use myScale like you would use scale in cases with horizontal zoom.

红尘作伴 2024-12-19 09:57:01

在与同样的问题作斗争之后,我想出了一个解决方法。
将此代码用于 setTransform 方法。

-(void)setTransform:(CGAffineTransform)transform
{
    CGAffineTransform constrainedTransform = CGAffineTransformIdentity;
    constrainedTransform.d = self.initialScale * transform.d;
    constrainedTransform.d = (constrainedTransform.d < MINIMUM_ZOOM_SCALE) ? MINIMUM_ZOOM_SCALE : constrainedTransform.d;
    
    [super setTransform:constrainedTransform];
}
                                                                          

从scrollViewWillBeginZooming 委托方法中设置initialScale 属性。

After struggling with the same issue, I was able to come up with a workaround.
Use this code for the setTransform method.

-(void)setTransform:(CGAffineTransform)transform
{
    CGAffineTransform constrainedTransform = CGAffineTransformIdentity;
    constrainedTransform.d = self.initialScale * transform.d;
    constrainedTransform.d = (constrainedTransform.d < MINIMUM_ZOOM_SCALE) ? MINIMUM_ZOOM_SCALE : constrainedTransform.d;
    
    [super setTransform:constrainedTransform];
}
                                                                          

Set the initialScale property from within the scrollViewWillBeginZooming delegate method.

血之狂魔 2024-12-19 09:57:01

如果您提供您正在尝试的示例代码,将会更有帮助,但我给您一些行来尝试。实际上你必须使内容尺寸宽度等于“320”,即等于iPhone的屏幕尺寸。

scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 45,320,480)];   
scrollView.contentSize = CGSizeMake(320,1000);
scrollView.showsVerticalScrollIndicator = YES;

MonoTouch 版本如下:

scrollView = new UIScrollView (new RectangleF (0, 45, 320, 480)) {
    ContentSize = new SizeF (320, 1000),
    ShowVerticalScrollIndicator = true
};

希望有帮助..:)
是的,如果有帮助,请不要忘记接受答案:D

It will be more helpful if you provide a sample code of what you are trying, but i am giving you some lines to try. Actually you have to make the content size width equal to "320" i.e. equal to the the screen size of iPhone.

scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 45,320,480)];   
scrollView.contentSize = CGSizeMake(320,1000);
scrollView.showsVerticalScrollIndicator = YES;

The MonoTouch version follows:

scrollView = new UIScrollView (new RectangleF (0, 45, 320, 480)) {
    ContentSize = new SizeF (320, 1000),
    ShowVerticalScrollIndicator = true
};

Hope it helps.. :)
and Yes dont forget to accept the answer if it helps :D

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文