2010-10-13 3 views
2

У меня возникают проблемы при работе с большим количеством UIButtons в моем интерфейсе. Мне было интересно, есть ли у кого из первых рук опыт с этим и как они это сделали?Дизайн пользовательского интерфейса - лучший способ справиться со многими UIButtons

При работе с 30-80 кнопками наиболее просто, несколько сложностей, вы просто используете UIButton или делаете что-то другое, например drawRect, отвечаете на события касания и получаете координаты события касания?

Лучший пример - это календарь, аналогичный календарю App App Calendar. Вы бы просто нарисовали большую часть дней, используя drawRect, а затем, когда вы нажмете кнопку, замените ее изображением или просто используйте UIButtons? Это не столько объем памяти или создание кнопок, но иногда происходят странные вещи с ними (предыдущий вопрос об этом) и проблемы с производительностью, оживляющие их.

Спасибо за любую помощь.

ответ

2

Если «странные вещи происходят» с вашими кнопками, вам нужно добраться до нижней части , почему. Переключение архитектур только для того, чтобы избежать проблемы, которую вы не понимаете (и может возникнуть снова), не кажется хорошей идеей.

-drawRect: работает путем рисования в контексте с растровой поддержкой. Это происходит, когда -displayIfNeeded вызывается после -setNeedsDisplay (или выполняет что-то еще, что неявно устанавливает флаг requireDisplay, например изменение размера представления с помощью contentMode = UIContentModeRedraw). Контекст с поддержкой растрового изображения затем компонуется на экране.

Кнопки работают, помещая различные компоненты (фоновое изображение, изображение переднего плана, текст) в разные слои. Текст рисуется, когда он изменяется и компонуется на экране; изображения просто компонуются непосредственно на экране.

«Лучший» способ делать вещи обычно представляет собой комбинацию из двух. Например, вы можете нарисовать текст и фоновое изображение в -drawRect: поэтому разные слои не нужно было компоновать во время рендеринга (вы получаете дополнительное ускорение, если ваше представление «непрозрачное»). Вероятно, вы хотите избежать полноэкранных анимаций с помощью drawRect: (и он не будет так хорошо интегрироваться с CoreAnimation), поскольку рисунок имеет тенденцию быть более дорогим, чем композитинг.

Но сначала я узнаю, что происходит с UIButton. Нечего беспокоиться о том, как можно ускорить работу, пока вы не узнаете, что такое медленные биты. Напиши код, чтобы его было легко поддерживать.UIButton не , что дорогой и -drawRect: не , что плохо (предположительно, это даже лучше, если вы используете -setNeedsDisplayInRect: для небольшого прямоугольника, но тогда вам нужно вычислить прямоугольник ...), но если вы хотите кнопку , используйте UIButton.

+0

Хммм, это заставило меня проверить одно, что зафиксировало это - хорошо, «странные вещи происходят». Который купил другой вопрос, если бы вы могли ответить. Раньше я подклассифицировал UIView, чтобы нарисовать некоторые строки и прочее, а затем в подклассе, который я создал, и добавил UIButtons к себе. Хотя он работал, он делал некоторые странные вещи и не отображался должным образом при нормальной нагрузке. Я вытащил код кнопки из подкласса и создал кнопки и добавил его в представление в моем основном классе, и он сработал. Что происходит? Я делаю большой нет нет, добавляя элементы в подкласс UIView в UIView? – Rudiger

+0

Нет ничего плохого, если вы вообще не добавляете subviews в -initWithBlah. Странные вещи могут произойти, если вы добавите их в -drawRect: (я думаю, что -layoutSubviews безопасен, но я не совсем уверен). –

+0

Хотя это не ответ на вопрос, который я искал, он исправил большинство моих проблем. Я рассмотрю ответы других людей, которые помогут решить мою проблему с производительностью. – Rudiger

1

Вместо использования 30-80 UIButtons я предпочту использовать изображения (если возможно, одно изображение или как можно меньше) и сравнить местоположение касания.

И если я должен создать кнопки, то, очевидно, не создаст для них 30-80 переменных. Я установлю и получаю тег представления, чтобы определить, какой из них прослушивается.

+0

Хмм, не так, как я бы угаданных. Когда-либо их оживляли? Представление? Мне нравится звук вашей последней части. Итак, сделайте одну кнопку, установите тег представления и другие предметы первой необходимости, такие как название, и просто повторно используйте его? – Rudiger

+1

Что я имею в виду по тегу, это не о повторном использовании одной кнопки. скажем, мне нужна кнопка 30. то вместо объявления 30 переменных для них я сохраню их в массиве с тегом. и в обработчике кнопок я использую тег отправителя для выполнения правильных задач. этот код будет менее запутанным. попытка оживить многие слои - не очень хорошая идея. u действительно должен думать, если у вас есть альтернатива. скажем, мне нужна сетка размером 10 х 10. поэтому мне потребуется 100 кнопок. вместо создания 100 кнопок я буду использовать одно единственное изображение в качестве фона сетки и касания, чтобы узнать, какая ячейка используется. – taskinoor

+1

, и в случае, если мне нужна различная анимация для всех ячеек одновременно и не может быть выполнена одним изображением, тогда, очевидно, потребуется более тщательный дизайн. Я использовал анимацию пути около 50 изображений одновременно без проблем, даже на устройстве 2g. но для достижения хорошей производительности требуется тщательный компромисс кодирования и дизайна. – taskinoor

1

Если это все, что вы анимируете, тогда вы можете создать кучу CALayers с их содержимым, установленным в CGImage. Вы должны сравнить местоположение касания, чтобы идентифицировать слой. У CALayers есть полезное свойство стиля, которое является NSDictionary, в котором вы можете хранить метаданные.

+0

Я думал, что занятие слоями может быть одним из способов. Итак, UIView с кучей добавленных CALayers, а затем сравните прикосновение, чтобы найти кнопку? – Rudiger

+0

Да, может быть, это боль, чтобы найти этот слой, но оптимизация анимации будет оптимизирована. – Ben

1

Я просто использую UIButtons, если не возникает особая проблема производительности, которая возникает. Однако, если у них есть аналогичные функции, такие как клавиатура, я сопоставляю их все с одним IBAction и различаю поведение, основанное на отправителе.

Какие конкретные проблемы с производительностью и анимацией вы используете?

+0

Анимация и иногда не отображается правильно.Я просто создаю их в коде, а не в nibs – Rudiger

+0

Покажите нам код! Это может быть проблемой удержания. –

1

Я недавно столкнулся с этой проблемой при разработке игры для iPhone. Я использовал UIButtons для хранения игровых плит, затем стилизовал их с прозрачными изображениями, цветами фона и текстом.

Все это хорошо работало для небольшого количества плиток. Однако, когда мы добрались до 50, производительность значительно снизилась. После очистки Google я обнаружил, что другие испытывали ту же проблему. Кажется, iPhone борется с множеством прозрачных кнопок на экране сразу. Не уверен, что это ошибка в коде UIButton или просто ограничение графического оборудования на устройстве, но в любом случае это не под вашим контролем в качестве программиста.

Моим решением было нарисовать доску вручную, используя Core Graphics. Сначала это казалось сложным, но на самом деле это было довольно легко. Я просто разместил один большой UIImageView на моем ViewController в Interface Builder, сделав его IBOutlet, чтобы я мог изменить его с Objective-C, а затем построил образ с помощью Core Graphics.

Поскольку UIImageView не обрабатывает краны, я использовал метод touchhesBegan моего UIViewController, а затем triangulated координаты 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]; 
} 
+0

Некоторый код, как вы его построили с помощью Core Graphics, был бы хорош. Также вы ответили, изменив изображение кнопки, когда пользователь нажал на нее? – Rudiger

+0

Хорошо, я добавил несколько примеров кода. Это ошпаренная версия того, что я делаю в своем приложении, но вам достаточно понять концепцию. Он обрабатывает касания и подчеркивает также плитку. Наслаждайтесь! – Axeva

Смежные вопросы