我在界面中处理大量UIButton时遇到了问题。我想知道是否有人有这方面的第一手经验以及他们是如何做到的?
当处理最简单的30-80个按钮时,您只需使用UIButton或做一些不同的事情,比如drawRect,响应触摸事件并获取触摸事件的坐标,这几个复杂吗?
最佳示例是日历,类似于Apples Calendar App。您是否只使用drawRect绘制大部分时间,然后单击按钮将其替换为图像或仅使用UIButtons?这不是内存占用或创建按钮,只是有时会发生奇怪的事情(之前有关它的问题)并且有性能问题为它们设置动画。
感谢您的帮助。
答案 0 :(得分:2)
如果您的按钮发生了“奇怪的事情”,您需要了解 why 的底部。切换架构只是为了避免你不理解的问题(并且可能再次出现)听起来不是一个好主意。
-drawRect:
通过绘制到位图支持的上下文来工作。当在-setNeedsDisplay之后调用-displayIfNeeded(或者执行隐式设置needsDisplay标志的其他操作,例如使用contentMode = UIContentModeRedraw调整视图大小)时,会发生这种情况。然后将位图支持的上下文合成到屏幕。
按钮的工作原理是将不同的组件(背景图像,前景图像,文本)放在不同的层中。文本在更改并合成到屏幕时绘制;图像只是直接合成到屏幕上。
“最好”的做事方式通常是两者的结合。例如,您可以在-drawRect中绘制文本和背景图像:因此不需要在渲染时合成不同的图层(如果您的视图是“不透明的”,则会获得额外的加速)。您可能希望通过drawRect避免全屏动画:(并且它与CoreAnimation不能很好地集成),因为绘图往往比合成更昂贵。
但首先,我会发现UIButton出了什么问题。在你真正找到慢速位之前,你可以更快地把事情做得更加令人担忧。编写代码以便于维护。 UIButton不 昂贵且-drawRect:不坏(如果你使用-setNeedsDisplayInRect:
作为一个小的矩形,可能会更好,但是你需要计算rect ...),但是如果你想要一个按钮,请使用UIButton。
答案 1 :(得分:1)
我宁愿使用图像(如果可能的话,单个图像或尽可能少的数字)而不是使用30-80个UIButton,而是比较触摸位置。
如果我必须创建按钮,那么显然不会为它们创建30-80个变量。我将设置并获取视图标记以确定哪个被点击。
答案 2 :(得分:1)
如果这是你动画的所有内容,那么你可以创建一堆CALayers,其内容设置为CGImage。您必须比较触摸位置以识别图层。 CALayers有一个有用的样式属性,它是一个NSDictionary,你可以存储元数据。
答案 3 :(得分:1)
我只是使用UIButton,除非碰巧遇到特定的性能问题。但是,如果它们具有类似的功能,例如键盘,我会将它们全部映射到一个IBAction,并根据发送者区分行为。
您遇到了哪些具体的性能和动画问题?
答案 4 :(得分:1)
我最近在为iPhone开发游戏时遇到了这个问题。我使用UIButtons来保存游戏牌,然后用透明图像,背景颜色和文字对它们进行风格化。
一切都适用于少量瓷砖。然而,一旦我们达到50左右,性能就会大幅下降。淘到谷歌后,我发现其他人也经历过同样的问题。看起来iPhone一下子屏幕上有很多透明按钮。不确定它是UIButton代码中的错误还是设备上图形硬件的限制,但不管怎样,它都是你作为程序员无法控制的。
我的解决方案是使用Core Graphics手动绘制板。起初它似乎令人生畏,但实际上它很容易。我刚刚在Interface Builder中的ViewController上放置了一个大的UIImageView,使它成为一个IBOutlet,所以我可以从Objective-C改变它,然后使用Core Graphics构建图像。
由于UIImageView不处理水龙头,我使用了UIViewController的touchesBegan方法,然后将触摸的x / y坐标三角测量到我游戏板上的精确图块。
董事会现在提交的时间不到十分之一秒。宾果!
如果您需要示例代码,请告诉我们。
更新:以下是我正在使用的代码的简化版本。应该足以让你获得要点。
// CoreGraphicsTestViewController.h
// CoreGraphicsTest
#import <UIKit/UIKit.h>
@interface CoreGraphicsTestViewController : UIViewController {
UIImageView *testImageView;
}
@property (retain, nonatomic) IBOutlet UIImageView *testImageView;
-(void) drawTile: (CGContextRef) ctx row: (int) rowNum col: (int) colNum isPressed: (BOOL) tilePressed;
@end
...和.m文件......
// CoreGraphicsTestViewController.m
// CoreGraphicsTest
#import "CoreGraphicsTestViewController.h"
#import <QuartzCore/QuartzCore.h>
#import <CoreGraphics/CoreGraphics.h>
@implementation CoreGraphicsTestViewController
@synthesize testImageView;
int iTileSize;
int iBoardSize;
- (void)viewDidLoad {
int iRow;
int iCol;
iTileSize = 75;
iBoardSize = 3;
[testImageView setBounds: CGRectMake(0, 0, iBoardSize * iTileSize, iBoardSize * iTileSize)];
CGRect rect = CGRectMake(0.0f, 0.0f, testImageView.bounds.size.width, testImageView.bounds.size.height);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
for (iRow = 0; iRow < iBoardSize; iRow++) {
for (iCol = 0; iCol < iBoardSize; iCol++) {
[self drawTile: context row: iRow col: iCol color: isPressed: NO];
}
}
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
[testImageView setImage: image];
UIGraphicsEndImageContext();
[super viewDidLoad];
}
- (void)dealloc {
[testImageView release];
[super dealloc];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView: testImageView];
if ((location.x >= 0) && (location.y >= 0) && (location.x <= testImageView.bounds.size.width) && (location.y <= testImageView.bounds.size.height)) {
UIImage *theIMG = testImageView.image;
CGRect rect = CGRectMake(0.0f, 0.0f, testImageView.bounds.size.width, testImageView.bounds.size.height);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
[theIMG drawInRect: rect];
iRow = location.y / iTileSize;
iCol = location.x / iTileSize;
[self drawTile: context row: iRow col: iCol color: isPressed: YES];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
[testImageView setImage: image];
UIGraphicsEndImageContext();
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UIImage *theIMG = testImageView.image;
CGRect rect = CGRectMake(0.0f, 0.0f, testImageView.bounds.size.width, testImageView.bounds.size.height);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
[theIMG drawInRect: rect];
[self drawTile: context row: iRow col: iCol isPressed: NO];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
[testImageView setImage: image];
UIGraphicsEndImageContext();
}
-(void) drawTile: (CGContextRef) ctx row: (int) rowNum col: (int) colNum isPressed: (BOOL) tilePressed {
CGRect rrect = CGRectMake((colNum * iTileSize), (rowNum * iTileSize), iTileSize, iTileSize);
CGContextClearRect(ctx, rrect);
if (tilePressed) {
CGContextSetFillColorWithColor(ctx, [[UIColor redColor] CGColor]);
} else {
CGContextSetFillColorWithColor(ctx, [[UIColor greenColor] CGColor]);
}
UIImage *theImage = [UIImage imageNamed:@"tile.png"];
[theImage drawInRect: rrect];
}