- objective-c - iOS 5 : Can you override UIAppearance customisations in specific classes?
- iphone - 如何将 CGFontRef 转换为 UIFont?
- ios - 以编程方式关闭标记的信息窗口 google maps iOS
- ios - Xcode 5 - 尝试验证存档时出现 "No application records were found"
我有一个 UIScrollView。在这里我有一个 UIView,它有一个负原点的框架 - 我需要限制 ScrollView ,这样你就不能滚动整个 View ..
我已经在此 ScrollView 中实现了缩放。
缩放时, ScrollView 将根据比例调整可缩放 View 的大小。但它不会调整原点。
所以如果我有一个框架为 {0, -500}, {1000, 1000}
的 View我缩小到 0.5 的比例,这将给我一个新的框架 {0, -500}, {500, 500}
显然这样不好,整个view都被scrollview缩小了。我希望框架为 {0, -250}, {500, 500}
我可以通过正确调整原点来修复 scrollViewDidZoom 方法中的一些问题。这确实有效,但缩放不平滑。在这里更改原点会导致它跳跃。
我在 UIView 的文档中注意到它说(关于 frame 属性):
Warning: If the transform property is not the identity transform, the value of this property is undefined and therefore should be ignored.
不太清楚这是为什么。
我是不是处理这个问题有误?修复它的最佳方法是什么?
谢谢
下面是我正在使用的测试应用程序的一些源代码:
在 View Controller 中..
- (void)viewDidLoad
{
[super viewDidLoad];
self.bigView = [[BigView alloc] initWithFrame: CGRectMake(0, -400, 1000, 1000)];
[self.bigScroll addSubview: bigView];
self.bigScroll.delegate = self;
self.bigScroll.minimumZoomScale = 0.2;
self.bigScroll.maximumZoomScale = 5;
self.bigScroll.contentSize = bigView.bounds.size;
}
-(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return bigView;
}
- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
// bigView.frame = CGRectMake(0, -400 * scrollView.zoomScale,
// bigView.frame.size.width, bigView.frame.size.height);
bigView.center = CGPointMake(500 * scrollView.zoomScale, 100 * scrollView.zoomScale);
}
然后在 View 中...
- (void)drawRect:(CGRect)rect
{
// Drawing code
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(ctx, [UIColor whiteColor].CGColor);
CGContextSetStrokeColorWithColor(ctx, [UIColor whiteColor].CGColor);
CGContextFillRect(ctx, CGRectMake(100, 500, 10, 10));
for (int i = 0; i < 1000; i += 100) {
CGContextStrokeRect(ctx, CGRectMake(0, i, 1000, 3));
}
}
请注意,这里的跳跃在较大的缩放比例下更为明显。在我的真实应用程序中,有更多的绘图和处理正在进行,跳跃在任何时候都更加明显。
最佳答案
您不必使用 frame 属性 - 鉴于 Apple 非常坚定的警告,您也不应该使用。在这种情况下,您通常可以使用 bounds
和 center
来实现您的结果。
在您的情况下,您可以忽略所有 subview 的属性。假设您的 subview 是 viewForZoomingInScrollView
,您可以使用 scrollView 的 contentOffset
和 zoomScale
属性
- (void) setMinOffsets:(UIScrollView*)scrollView
{
CGFloat minOffsetX = MIN_OFFSET_X*scrollView.zoomScale;
CGFloat minOffsetY = MIN_OFFSET_Y*scrollView.zoomScale;
if ( scrollView.contentOffset.x < minOffsetX
|| scrollView.contentOffset.y < minOffsetY ) {
CGFloat offsetX = (scrollView.contentOffset.x > minOffsetX)?
scrollView.contentOffset.x : minOffsetX;
CGFloat offsetY = (scrollView.contentOffset.y > minOffsetY)?
scrollView.contentOffset.y : minOffsetY;
scrollView.contentOffset = CGPointMake(offsetX, offsetY);
}
}
从您的 scrollView 委托(delegate)中的 scrollViewDidScroll
和 scrollViewDidZoom
调用它。这应该可以顺利进行,但如果您有疑问,您也可以通过子类化 scrollView 并使用 layoutSubviews
调用它来实现它。在他们的 PhotoScroller 示例中,Apple 通过覆盖 layoutSubviews
使 scrollView 的内容居中 - 尽管他们疯狂地忽略了自己的警告并调整 subview 的 frame 属性来实现这一点。
更新
上述方法消除了 ScrollView 达到其极限时的“弹跳”。如果您想保留反弹,您可以直接更改 View 的中心属性:
- (void) setViewCenter:(UIScrollView*)scrollView
{
UIView* view = [scrollView subviews][0];
CGFloat centerX = view.bounds.size.width/2-MIN_OFFSET_X;
CGFloat centerY = view.bounds.size.height/2-MIN_OFFSET_Y;
centerX *=scrollView.zoomScale;
centerY *=scrollView.zoomScale;
view.center = CGPointMake(centerX, centerY);
}
更新 2
从您更新的问题(带有代码)中,我可以看出这些解决方案都不能解决您的问题。似乎正在发生的事情是,您的偏移量越大,变焦运动变得越不稳定。偏移量为 100 点时, Action 仍然相当流畅,但偏移量为 500 点时,则粗糙得令人无法接受。这部分与您的 drawRect
例程有关,部分与 scrollView 中正在进行的(太多)重新计算有关以显示正确的内容。所以我有另一个解决方案......
在您的 viewController 中,将您的 customView 的边界/框架原点设置为正常 (0,0)。我们将使用图层来偏移内容。您需要将 QuartzCore 框架添加到您的项目中,并将其#import 到您的自定义 View 中。
在自定义 View 中初始化两个 CAShapeLayers - 一个用于框,另一个用于线。如果它们共享相同的填充和描边,你将只需要一个 CAShapeLayer(对于这个例子,我改变了你的填充和描边颜色)。每个 CAShapeLayer 都有它自己的 CGContext,你可以用颜色、线宽等每层初始化一次。然后要让 CAShapelayer 完成它的绘制,你所要做的就是用 CGPath 设置它的 path
属性。
#import "CustomView.h"
#import <QuartzCore/QuartzCore.h>
@interface CustomView()
@property (nonatomic, strong) CAShapeLayer* shapeLayer1;
@property (nonatomic, strong) CAShapeLayer* shapeLayer2;
@end
@implementation CustomView
#define MIN_OFFSET_X 100
#define MIN_OFFSET_Y 500
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self initialiseLayers];
}
return self;
}
- (void) initialiseLayers
{
CGRect layerBounds = CGRectMake( MIN_OFFSET_X,MIN_OFFSET_Y
, self.bounds.size.width + MIN_OFFSET_X
, self.bounds.size.height+ MIN_OFFSET_Y);
self.shapeLayer1 = [[CAShapeLayer alloc] init];
[self.shapeLayer1 setFillColor:[UIColor clearColor].CGColor];
[self.shapeLayer1 setStrokeColor:[UIColor yellowColor].CGColor];
[self.shapeLayer1 setLineWidth:1.0f];
[self.shapeLayer1 setOpacity:1.0f];
self.shapeLayer1.anchorPoint = CGPointMake(0, 0);
self.shapeLayer1.bounds = layerBounds;
[self.layer addSublayer:self.shapeLayer1];
设置界限是关键。与裁剪其 subview 的 View 不同,CALayers 将绘制超出其超层的边界。您将开始在 View 顶部上方绘制 MIN_OFFSET_Y
点,在左侧绘制 MIN_OFFSET_X
点。这允许您在 ScrollView 的内容 View 之外绘制内容,而无需 ScrollView 做任何额外的工作。
Unlike views, a superlayer does not automatically clip the contents of sublayers that lie outside its bounds rectangle. Instead, the superlayer allows its sublayers to be displayed in their entirety by default.
(Apple Docs, Building a Layer Hierarchy)
self.shapeLayer2 = [[CAShapeLayer alloc] init];
[self.shapeLayer2 setFillColor:[UIColor blueColor].CGColor];
[self.shapeLayer2 setStrokeColor:[UIColor clearColor].CGColor];
[self.shapeLayer2 setLineWidth:0.0f];
[self.shapeLayer2 setOpacity:1.0f];
self.shapeLayer2.anchorPoint = CGPointMake(0, 0);
self.shapeLayer2.bounds = layerBounds;
[self.layer addSublayer:self.shapeLayer2];
[self drawIntoLayer1];
[self drawIntoLayer2];
}
为每个形状层设置一条贝塞尔曲线路径,然后传入:
- (void) drawIntoLayer1 {
UIBezierPath* path = [[UIBezierPath alloc] init];
[path moveToPoint:CGPointMake(0,0)];
for (int i = 0; i < self.bounds.size.height+MIN_OFFSET_Y; i += 100) {
[path moveToPoint:
CGPointMake(0,i)];
[path addLineToPoint:
CGPointMake(self.bounds.size.width+MIN_OFFSET_X, i)];
[path addLineToPoint:
CGPointMake(self.bounds.size.width+MIN_OFFSET_X, i+3)];
[path addLineToPoint:
CGPointMake(0, i+3)];
[path closePath];
}
[self.shapeLayer1 setPath:path.CGPath];
}
- (void) drawIntoLayer2 {
UIBezierPath* path = [UIBezierPath bezierPathWithRect:
CGRectMake(100+MIN_OFFSET_X, MIN_OFFSET_Y, 10, 10)];
[self.shapeLayer2 setPath:path.CGPath];
}
这避免了对 drawRect
的需要 - 如果您更改路径属性,您只需要重新绘制图层。即使您确实像调用 drawRect 一样频繁地更改路径属性,绘图现在也应该明显更有效。由于 path
是一个动画属性,如果需要,您还可以免费获得动画。
在你的情况下,我们只需要设置一次路径,所以所有的工作都在初始化时完成一次。
现在您可以从 scrollView 委托(delegate)方法中删除任何居中代码,不再需要它了。
关于ios - UIScrollView 缩小具有 -ve 原点的 View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16361810/
抱歉这个奇怪的标题,但是,这正是我所需要的。我知道这是可以做到的,因为我见过其他应用程序这样做。 基本上,我的应用程序有一个启用分页的大 ScrollView ,其中包含一些嵌套的 ScrollVie
我还没有尝试过,但我假设一旦我知道用户想要在子 ScrollView 中滚动,我就必须禁用父 ScrollView 的滚动,对吗? 两个 ScrollView 都是水平滚动的。 如何暂时禁用父级的滚动
我需要实现这个方法: - (CGRect)zoomRectForScale:(float)scale withCenter:(CGPoint)center { 但我不知道如何获得我需要的中心坐标。通常
我想根据 UIAccelerometer 值滚动 ScrollView 。实现这一目标的最佳方法是什么? 最初,我根据获得的加速度计值将内容偏移设置为一个值。然后在每个 scrollViewDidEn
我有一个 UIScrollView,我需要底部淡入透明,这样它就不会突然切断内容。 UIScrollView 的背景是自定义颜色。这是我到目前为止所拥有的,但图层显示为白色,而不是自定义颜色。这就是我
我有一个 UIScrollviews 彼此存在的层次结构。 如何将特定区域的滑动事件重定向到内部 ScrollView ? 最佳答案 如果您将 UIScrollViews 设置为只能在一个轴或另一轴上
在我的应用程序中,我有一个扩展 UIScrollView 并在用户滚动时填充其内容的 View 。但是,如果用户滚动太快,则 UIScrollView 内填充的 View 不会及时创建,您实际上可以看
我有一个包含内容的 UIScroll View 。如果该内容溢出,使 ScrollView 可滚动,我想将 View 的底部设置为某种颜色。如果没有,我想将其设置为不同的颜色。 我的问题是,我不知道如
我有一个 ScrollView ,其中包含一个 UIImageView,以及一个额外的 UIScrollView 和 UIImageView。 我想要实现的是独立缩放和平移每个 ScrollView
类似的问题也有人问过这个,但我的困境其实和他们正好相反。我有一个全屏、分页 UIScrollView,每个页面都是屏幕的大小。在其中,我有一些页面本身就是 UIScrollViews,它们的宽度大于屏
我有一个 UIScrollView 和另一个 UIScrollView 。它们都水平滚动并且具有 pagingEnabled = YES。假设我开始滚动内部 ScrollView 并到达最右边界。如果
我有一个 UIScrollView,里面有一个(自定义)UIView。 在我的 scrollViewDidScroll 方法中,我正在调用 [myCustomView setNeedsDisplay]
我有一个水平滚动的 UICollectionView,其中填充了垂直滚动的 UITableViews(两者都是 UISCrollView 的子类)。当滚动手势开始沿任一方向滚动时,在其减速完成之前不会
iOS 8, swift 。我试图在水平 ScrollView 上创建垂直 ScrollView 。它们都是 UIScrollView。垂直 ScrollView 允许从底部向上滑动 View 。顶部
我需要一个分页的 UIScrollView,它以 UIScreenEdgePanGestureRecognizer 的方式检测屏幕边缘的平移,而不是像 UIPanGestureRecognizer 那
假设我有多个 ScrollView ,并且我希望在任何给定时间只打开其中一个 (scrollView.contentOffset != 0)。因此,当 scroll view 1 打开且 scroll
我在分页 UIScrollView(外部)中的 VC 中有 UIScrollView(内部 - UICollectionView 是诚实的)。两者都是水平的。当我向内滚动到边缘(左侧或右侧)时,它开始
如何在不干扰现有 UIScrollView 的情况下从现有 UIScrollView 获取重复的 UIScrollView。 第一个 ScrollView , UIScrollView *firstS
我的应用程序中有一个点,我删除了一个 ScrollView 并添加了另一个。我希望新 ScrollView 中也能出现上一个 ScrollView 中的相同手势。我尝试过: s
请告诉我如何在类似嵌套进程的 ScrollView 中设置 ScrollView 。 以下代码部分有效。 int x=10; int y=10; for(int i=0; i<5; i++) {
我是一名优秀的程序员,十分优秀!