2012-07-27 4 views
0

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

Я использую несколько обычных UIAlertViews в своем приложении. У некоторых есть 2 кнопки, у некоторых есть 3 кнопки, а у пары есть 2 кнопки и текстовое поле. Однако все имеют ту же проблему. Когда вы вызываете [someAlertView show]; представление предупреждения появляется как обычно, но затем внезапно его графический контекст, кажется, поврежден, как вы можете видеть на скриншоте.

UIAlertView Rendered incorrectly

Это происходит на обоих iPhone и IPad тренажеров (как 5.0 и 5.1), так и бывает на устройстве IPAD и iPhone4S, а также.

Изображение, показывающее все, что находится за предупреждением.

Предупреждение по-прежнему работает, я могу щелкнуть по кнопкам, ввести текстовое поле, а затем, когда он отклонит методы делегата, вызывается правильно, и все возвращается к нормальному состоянию. Когда alertView появляется снова, происходит то же самое.

Представление за предупреждением представляет собой подклассу UIScrollView с размером содержимого примерно 4000 пикселей на 1000 с использованием UIImage в качестве фона. Файл png в основном прозрачен, поэтому размер памяти составляет около 80 КБ, а в телефоне нет проблем с его воспроизведением - просмотр прокрутки по-прежнему полностью реагирует и не замедляется. Он также имеет таймер CADisplayLink, прикрепленный к нему как часть подкласса. Я попытался отключить это непосредственно перед отображением alertView, но это не имеет значения, поэтому я сомневаюсь, что это проблема.

Это приложение является частичным переписанием того, что я сделал для университетского проекта, и что он может отображать UIAlertViews поверх вершины scrollView того же размера и подкласса без проблем. Разница между этим приложением и тем, что в моем старом приложении, я подклассифицировал UIAlertView для добавления дополнительных вещей, таких как pickerView, однако я решил, что мне не понравилось, как он выглядел так, что все вышло из предупреждения, и я просто придерживаясь стандартного UIAlertView.

Это как alertView на скриншоте называется:

- (IBAction)loadSimulation:(id)sender { 
    importAlert = [[UIAlertView alloc] initWithTitle:@"Load Simulation" message:@"Enter Filename:" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Load", nil]; 
    [importAlert setAlertViewStyle:UIAlertViewStylePlainTextInput]; 
    [importAlert showPausingSimulation:self.simulationView]; //Calling [importAlert show]; makes no difference. 
    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) { 
     [self hideOrganiser]; //Not an issue as the problem occurs on iPad as well. 
    } 
} 

При этом, как категоризированного AlertView, чтобы добавить возможность остановить ссылку scrollViews CADisplay.

@interface UIAlertView(pauseDisplayLink) 
- (void)showPausingSimulation:(UILogicSimulatorView*)simulationView; 
@end 

@implementation UIAlertView(pauseDisplayLink) 

- (void)showPausingSimulation:(UILogicSimulatorView *)simulationView { 
    [simulationView stopRunning]; 
    [simulationView removeDisplayLink]; //displayLink needs to be removed from the run loop, otherwise it will keep going in the background and get corrupted. 
    [self show]; 
} 

У меня нет предупреждений о памяти, когда это происходит, поэтому я сомневаюсь, что это из-за нехватки ресурсов.

Неужели кто-нибудь сталкивался с такой проблемой раньше? Если вам нужна дополнительная информация, я могу попытаться ее предоставить, но я ограничен тем, какой код я могу опубликовать. Любая помощь была бы оценена, я пытался решить это в течение двух недель и не могу понять.


Edit: Оказывается, что это не AlertView на всех (или, вернее, не только alertView), так как эта проблема уходит, когда я извлекаю вид прокрутки позади него, так что должно быть некоторые между ними. Это код для моего UIScrollView подкласса: .h файл: #import #import

@class ECSimulatorController; 
@interface UILogicSimulatorView : UIScrollView { 
    CADisplayLink *displayLink; 
    NSInteger _updateRate; 
    ECSimulatorController* _hostName; 
} 

@property (nonatomic) NSInteger updateRate; 
@property (nonatomic, strong) ECSimulatorController* hostName; 

- (void) removeDisplayLink; 
- (void) reAddDisplayLink; 

- (void) displayUpdated:(CADisplayLink*)timer; 
- (void) startRunning; 
- (void) stopRunning; 
- (void) refreshRate:(NSInteger)rate; 

- (void) setHost:(id)host; 

- (void)setMinimumNumberOfTouches:(NSInteger)touches; 
- (void)setMaximumNumberOfTouches:(NSInteger)touches; 

@end 

.м файл:

#import "UILogicSimulatorView.h" 
#import "ECSimulatorController.h" 
#import <QuartzCore/QuartzCore.h> 

@implementation UILogicSimulatorView 

@synthesize updateRate = _updateRate; 
@synthesize hostName = _hostName; 

- (void)reAddDisplayLink { 
    [displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; //allows the display link to be re-added to the run loop after having been removed. 
} 

- (void)removeDisplayLink { 
    [displayLink removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; //allows the display link to be removed from the Run loop without deleting it. Removing it is essential to prevent corruption between the games and the simulator as both use CADisplay link, and only one can be in the run loop at a given moment. 
} 

- (void)startRunning { 
    [self refreshRate:self.updateRate]; 
    [displayLink setPaused:NO]; 
} 

- (void)refreshRate:(NSInteger)rate { 
    if (rate > 59) { 
     rate = 59; //prevent the rate from being set too an undefined value. 
    } 
    NSInteger frameInterval = 60 - rate; //rate is the number of frames to skip. There are 60FPS, so this converts to frame interval. 
    [displayLink setFrameInterval:frameInterval]; 
} 

- (void)stopRunning { 
    [displayLink setPaused:YES]; 
} 

- (void)displayUpdated:(CADisplayLink*)timer { 
    //call the function that the snakeController host needs to update 
    [self.hostName updateStates]; 
} 

- (void)setHost:(ECSimulatorController*)host; 
{ 
    self.hostName = host; //Host allows the CADisplay link to call a selector in the object which created this one. 
} 

- (id)initWithFrame:(CGRect)frame 
{ 
    //Locates the UIScrollView's gesture recogniser 
    if(self = [super initWithFrame:frame]) 
    { 
     [self setMinimumNumberOfTouches:2]; 
     displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayUpdated:)]; //CADisplayLink will update the logic gate states. 
     self.updateRate = 1; 
     [displayLink setPaused:YES]; 
    } 
    return self; 
} 

- (void)setMinimumNumberOfTouches:(NSInteger)touches{ 
    for (UIGestureRecognizer *gestureRecognizer in [self gestureRecognizers]) 
    { 
     if([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) 
     { 
      //Changes the minimum number of touches to 'touches'. This allows the UIPanGestureRecogniser in the object which created this one to work with one finger. 
      [(UIPanGestureRecognizer*)gestureRecognizer setMinimumNumberOfTouches:touches]; 
     } 
    } 
} 

- (void)setMaximumNumberOfTouches:(NSInteger)touches{ 
    for (UIGestureRecognizer *gestureRecognizer in [self gestureRecognizers]) 
    { 
     if([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) 
     { 
      //Changes the maximum number of touches to 'touches'. This allows the UIPanGestureRecogniser in the object which created this one to work with one finger. 
      [(UIPanGestureRecognizer*)gestureRecognizer setMaximumNumberOfTouches:touches]; 
     } 
    } 
} 

@end 
+0

«Хм, неважно, мне не разрешено размещать изображения? Как бесполезно». Это ваш первый пост. Поэтому мы вам не доверяем. Это один из многих преимуществ SO! – dasdom

+0

Я понимаю, почему это просто раздражает, что вокруг так много спамеров, что такие меры необходимы, вот и все, что я получаю. –

+0

Вы пытаетесь показать вид предупреждения из другого потока (например, в фоновом режиме)? Помните: всегда делайте UI-материал ** на главной теме! –

ответ

0

Я знаю, что слишком поздно для ответа на этот вопрос. В последнее время я испытал эту же проблему.

My Case: Добавлена ​​пара пользовательских UIViews с фоновыми изображениями и некоторыми элементами управления для просмотра прокрутки с эффектом тени. Я также установил shadowOffset.

Решение: После некоторых пошагового анализа, я обнаружил, что установка setShadowOpacity вызвала проблему рендеринга для меня. Когда я прокомментировал эту строку кода, она вылечила UIAlertView до нормального внешнего вида.

Подробнее: Чтобы убедиться, что я создал новый проект, имитирующий оригинальный ui с помощью shadowOpacity. Но это не вызвало проблему рендеринга, как я ожидал. Поэтому я не уверен в первопричине. Для меня это было setShadowOpacity.

+0

Никогда не поздно ответить на вопрос. Сначала я не был уверен, что использовал setShadowOpacity в любом месте, но странный глюк просто показал свое уродливое лицо в другой части приложения. После немного копания, оказывается, что внутри шаблона, который я сделал для этого приложения, вызывается setShadowOpacity. Я прокомментировал эту строку и глюк был излечен (я даже не могу вспомнить, почему я назвал этот метод в первую очередь!). Большое спасибо: D –

+0

Добро пожаловать! Счастлив, что это сработало :) –

1

Ну, мне удалось найти решение этого. На самом деле это, вероятно, просто маскирует проблему, а не находит причину маршрута, но в этот момент я возьму ее.

Первый некоторый код:

@interface UIView (ViewCapture) 
- (UIImage*)captureView; 
- (UIImage*)captureViewInRect:(CGRect)rect; 
@end 

@implementation UIView (ViewCapture) 

- (UIImage*)captureView { 
    return [self captureViewInRect:self.frame]; 
} 

- (UIImage*)captureViewInRect:(CGRect)rect 
{  
    UIGraphicsBeginImageContext(rect.size); 
    CGContextRef context = UIGraphicsGetCurrentContext(); 
    [self.layer renderInContext:context]; 
    UIImage *screenShot = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 
    return screenShot;  
} 
@end 

- (void)showPausingSimulation:(UILogicSimulatorView *)simulationView { 
    [simulationView stopRunning]; 
    UIView* superView = simulationView.superview; 
    CGPoint oldOffset = simulationView.contentOffset; 
    for (UIView* subview in simulationView.subviews) { 
     //offset subviews so they appear when content offset is (0,0) 
     CGRect frame = subview.frame; 
     frame.origin.x -= oldOffset.x; 
     frame.origin.y -= oldOffset.y; 
     subview.frame = frame; 
    } 
    simulationView.contentOffset = CGPointZero; //set the offset to (0,0) 
    UIImage* image = [simulationView captureView]; //Capture the frame of the scrollview 
    simulationView.contentOffset = oldOffset; //restore the old offset 
    for (UIView* subview in simulationView.subviews) { 
     //Restore the original positions of the subviews 
     CGRect frame = subview.frame; 
     frame.origin.x += oldOffset.x; 
     frame.origin.y += oldOffset.y; 
     subview.frame = frame; 
    } 
    [simulationView setHidden:YES]; 
    UIImageView* imageView = [[UIImageView alloc] initWithFrame:simulationView.frame]; 
    [imageView setImage:image]; 
    [imageView setTag:999]; 
    [superView addSubview:imageView]; 
    [imageView setHidden:NO]; 
    superView = nil; 
    imageView = nil; 
    image = nil; 
    [self show]; 
} 

- (void)dismissUnpausingSimulation:(UILogicSimulatorView *)simulationView { 
    UIView* superView = simulationView.superview; 
    UIImageView* imageView = (UIImageView*)[superView viewWithTag:999]; 
    [imageView removeFromSuperview]; 
    imageView = nil; 
    superView = nil; 
    [simulationView setHidden:NO]; 
    [simulationView startRunning]; 
} 

Затем модифицируя отклонять метод делегата в моем классе, чтобы иметь эту линию:

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { 
    [alertView dismissUnpausingSimulation:self.simulationView]; 
    ... 

Когда тревога вид называется, но до того, как показано, я необходимо скрыть симулятор, чтобы предотвратить его развращение. Однако просто скрывать это некрасиво, так как тогда все видно позади - это пустой вид.

Чтобы исправить это, я сначала создаю UIImage из графического контекста просмотра симулятора. Затем я создаю UIImageView с тем же фреймом, что и симулятор, и устанавливаю UIImage как его изображение. Затем я скрываю вид симулятора (устраняя проблему предупреждения) и добавляю свой новый UIImageView в супервизор симуляторов. Я также установил тег изображения, чтобы найти его позже.

Когда предупреждение отклоняется, изображение будет восстановлено на основе его тега и удалено из его супервизора. Затем симулятор не скрыт.

В результате проблема рендеринга исчезла.

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