Дизайн пользовательского интерфейса - лучший способ справиться со многими кнопками UIB - PullRequest
2 голосов
/ 14 октября 2010

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

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

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

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

Ответы [ 5 ]

2 голосов
/ 14 октября 2010

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

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

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

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

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

1 голос
/ 19 октября 2010

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

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

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

Поскольку UIImageView не обрабатывает касания,Я использовал метод touchesBegan моего UIViewController, а затем триангулировал координаты 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];
}
1 голос
/ 14 октября 2010

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

1 голос
/ 14 октября 2010

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

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

1 голос
/ 14 октября 2010

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...