Настройка действия кнопки «Назад» в контроллере навигации

ios iphone cocoa-touch uinavigationcontroller uibarbuttonitem

161476 просмотра

29 ответа

Я пытаюсь переписать действие по умолчанию кнопки «Назад» в контроллере навигации. Я предоставил цели действие на пользовательской кнопке. Странно то, что при назначении его через атрибут backbutton он не обращает на них внимания, а просто выскакивает из текущего представления и возвращается к корню:

UIBarButtonItem *backButton = [[UIBarButtonItem alloc] 
                                  initWithTitle: @"Servers" 
                                  style:UIBarButtonItemStylePlain 
                                  target:self 
                                  action:@selector(home)];
self.navigationItem.backBarButtonItem = backButton;

Как только я установил его через leftBarButtonItemon, navigationItemон вызывает мое действие, но кнопка выглядит как круглая, а не как стрелка назад:

self.navigationItem.leftBarButtonItem = backButton;

Как я могу заставить его вызывать свое пользовательское действие, прежде чем вернуться к корневому представлению? Есть ли способ перезаписать обратное действие по умолчанию, или есть метод, который всегда вызывается при выходе из представления ( viewDidUnloadне делает этого)?

Автор: Parrots Источник Размещён: 25.07.2019 01:51

Ответы (29)


363 плюса

Попробуйте вставить это в контроллер вида, где вы хотите обнаружить нажатие:

-(void) viewWillDisappear:(BOOL)animated {
    if ([self.navigationController.viewControllers indexOfObject:self]==NSNotFound) {
       // back button was pressed.  We know this is true because self is no longer
       // in the navigation stack.  
    }
    [super viewWillDisappear:animated];
}
Автор: William Jockusch Размещён: 10.08.2010 04:20

174 плюса

Я реализовал расширение UIViewController-BackButtonHandler . Для этого не нужно создавать подклассы, просто поместите это в ваш проект и переопределите navigationShouldPopOnBackButtonметод в UIViewControllerклассе:

-(BOOL) navigationShouldPopOnBackButton {
    if(needsShowConfirmation) {
        // Show confirmation alert
        // ...
        return NO; // Ignore 'Back' button this time
    }
    return YES; // Process 'Back' button click and Pop view controler
}

Скачать пример приложения .

Автор: onegray Размещён: 02.10.2013 08:28

42 плюса

В отличие от Амаграммера, это возможно. Вы должны подкласс вашего navigationController. Я все объяснил здесь (включая пример кода).

Автор: HansPinckaers Размещён: 28.11.2009 01:43

13 плюса

Swift версия:

(из https://stackoverflow.com/a/19132881/826435 )

В вашем контроллере представления вы просто соблюдаете протокол и выполняете все необходимые действия:

extension MyViewController: NavigationControllerBackButtonDelegate {
    func shouldPopOnBackButtonPress() -> Bool {
        performSomeActionOnThePressOfABackButton()
        return false
    }
}

Затем создайте класс, скажем NavigationController+BackButton, и просто скопируйте и вставьте код ниже:

protocol NavigationControllerBackButtonDelegate {
    func shouldPopOnBackButtonPress() -> Bool
}

extension UINavigationController {
    public func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
        // Prevents from a synchronization issue of popping too many navigation items
        // and not enough view controllers or viceversa from unusual tapping
        if viewControllers.count < navigationBar.items!.count {
            return true
        }

        // Check if we have a view controller that wants to respond to being popped
        var shouldPop = true
        if let viewController = topViewController as? NavigationControllerBackButtonDelegate {
            shouldPop = viewController.shouldPopOnBackButtonPress()
        }

        if (shouldPop) {
            DispatchQueue.main.async {
                self.popViewController(animated: true)
            }
        } else {
            // Prevent the back button from staying in an disabled state
            for view in navigationBar.subviews {
                if view.alpha < 1.0 {
                    UIView.animate(withDuration: 0.25, animations: {
                        view.alpha = 1.0
                    })
                }
            }

        }

        return false
    }
}
Автор: kgaidis Размещён: 17.12.2015 08:12

5 плюса

Это невозможно сделать напрямую. Есть пара альтернатив:

  1. Создайте свой собственный кастом, UIBarButtonItemкоторый проверяется при нажатии и появляется, если тест пройден
  2. Проверьте содержимое поля формы с помощью UITextFieldметода делегата, например -textFieldShouldReturn:, который вызывается после нажатия кнопки Returnили Doneна клавиатуре.

Недостатком первого варианта является то, что стиль стрелки влево на кнопке «Назад» не может быть доступен с помощью пользовательской кнопки панели. Таким образом, вы должны использовать изображение или перейти с обычной кнопки стиля.

Второй вариант удобен тем, что вы возвращаете текстовое поле в методе делегата, поэтому вы можете настроить свою логику проверки на конкретное текстовое поле, отправленное методу обратного вызова делегата.

Автор: Alex Reynolds Размещён: 25.05.2010 07:58

5 плюса

По некоторым причинам многопоточность, решение, упомянутое @HansPinckaers, мне не подошло, но я нашел очень простой способ поймать прикосновение к кнопке «Назад», и я хочу закрепить это здесь на случай, если это поможет избежать многочасовых обманов кто-нибудь другой. Трюк действительно прост: просто добавьте прозрачную UIButton в качестве подпредставления к вашему UINavigationBar и установите для него селекторы, как если бы это была настоящая кнопка! Вот пример, использующий Monotouch и C #, но перевод в цель-c не должен быть слишком сложным для поиска.

public class Test : UIViewController {
    public override void ViewDidLoad() {
        UIButton b = new UIButton(new RectangleF(0, 0, 60, 44)); //width must be adapted to label contained in button
        b.BackgroundColor = UIColor.Clear; //making the background invisible
        b.Title = string.Empty; // and no need to write anything
        b.TouchDown += delegate {
            Console.WriteLine("caught!");
            if (true) // check what you want here
                NavigationController.PopViewControllerAnimated(true); // and then we pop if we want
        };
        NavigationController.NavigationBar.AddSubview(button); // insert the button to the nav bar
    }
}

Интересный факт: в целях тестирования и чтобы найти подходящие размеры для моей фальшивой кнопки, я установил синий цвет ее фона ... И он отображается за кнопкой "Назад"! Во всяком случае, он все еще ловит любое прикосновение, нацеленное на оригинальную кнопку.

Автор: psycho Размещён: 06.07.2011 11:46

3 плюса

Этот метод позволяет изменить текст кнопки «назад», не затрагивая заголовок любого из контроллеров представления или не видя изменения текста кнопки «Назад» во время анимации.

Добавьте это к методу init в вызывающем контроллере представления:

UIBarButtonItem *temporaryBarButtonItem = [[UIBarButtonItem alloc] init];   
temporaryBarButtonItem.title = @"Back";
self.navigationItem.backBarButtonItem = temporaryBarButtonItem;
[temporaryBarButtonItem release];
Автор: Jason Moore Размещён: 23.07.2010 01:36

3 плюса

Самый простой способ

Вы можете использовать методы делегата UINavigationController. Метод willShowViewControllerвызывается, когда нажата кнопка «Назад» вашего ВК.

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated;
Автор: Xar E Ahmer Размещён: 18.09.2014 11:31

3 плюса

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

-(void) overrideBack{

    UIButton *transparentButton = [[UIButton alloc] init];
    [transparentButton setFrame:CGRectMake(0,0, 50, 40)];
    [transparentButton setBackgroundColor:[UIColor clearColor]];
    [transparentButton addTarget:self action:@selector(backAction:) forControlEvents:UIControlEventTouchUpInside];
    [self.navigationController.navigationBar addSubview:transparentButton];


}

Теперь предоставьте необходимую функциональность в следующем методе:

-(void)backAction:(UIBarButtonItem *)sender {
    //Your functionality
}

Все, что он делает - это закрывает кнопку назад прозрачной кнопкой;)

Автор: Sarasranglt Размещён: 21.08.2015 11:13

2 плюса

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

Вы можете приблизиться (без стрелки), создав обычную кнопку и скрыв кнопку возврата по умолчанию:

self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithTitle:@"Servers" style:UIBarButtonItemStyleDone target:nil action:nil] autorelease];
self.navigationItem.hidesBackButton = YES;
Автор: Meltemi Размещён: 31.07.2009 11:08

2 плюса

Там более простой способ, просто наследование метода делегата из UINavigationBarи переопределить в ShouldPopItemметоде .

Автор: jazzyjef2002 Размещён: 27.08.2013 06:49

2 плюса

Вот мое решение Swift. В вашем подклассе UIViewController переопределите метод navigationShouldPopOnBackButton.

extension UIViewController {
    func navigationShouldPopOnBackButton() -> Bool {
        return true
    }
}

extension UINavigationController {

    func navigationBar(navigationBar: UINavigationBar, shouldPopItem item: UINavigationItem) -> Bool {
        if let vc = self.topViewController {
            if vc.navigationShouldPopOnBackButton() {
                self.popViewControllerAnimated(true)
            } else {
                for it in navigationBar.subviews {
                    let view = it as! UIView
                    if view.alpha < 1.0 {
                        [UIView .animateWithDuration(0.25, animations: { () -> Void in
                            view.alpha = 1.0
                        })]
                    }
                }
                return false
            }
        }
        return true
    }

}
Автор: AutomatonTec Размещён: 14.03.2015 10:12

2 плюса

Решение onegray небезопасно. Согласно официальным документам Apple, https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/CustomizingExistingClasses/CustomizingExistingClasses.html мы не должны этого делать.

«Если имя метода, объявленного в категории, совпадает с именем метода в исходном классе или методом в другой категории в том же классе (или даже в суперклассе), поведение не определено относительно того, какая реализация метода используется во время выполнения. Это менее вероятно, будет проблемой, если вы используете категории со своими собственными классами, но могут вызвать проблемы при использовании категорий для добавления методов в стандартные классы Cocoa или Cocoa Touch. "

Автор: user2612791 Размещён: 02.11.2015 06:02

2 плюса

Используя Swift:

override func viewWillDisappear(animated: Bool) {
    super.viewWillDisappear(animated)
    if self.navigationController?.topViewController != self {
        print("back button tapped")
    }
}
Автор: Murray Sagal Размещён: 19.04.2016 02:51

2 плюса

Вот версия Swon 3 ответа @oneway для отлавливания события кнопки возврата на панели навигации до того, как оно будет запущено. Как UINavigationBarDelegateнельзя использовать UIViewController, вам нужно создать делегат, который будет запускаться при navigationBar shouldPopвызове.

@objc public protocol BackButtonDelegate {
      @objc optional func navigationShouldPopOnBackButton() -> Bool 
}

extension UINavigationController: UINavigationBarDelegate  {

    public func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {

        if viewControllers.count < (navigationBar.items?.count)! {                
            return true
        }

        var shouldPop = true
        let vc = self.topViewController

        if vc.responds(to: #selector(vc.navigationShouldPopOnBackButton)) {
            shouldPop = vc.navigationShouldPopOnBackButton()
        }

        if shouldPop {
            DispatchQueue.main.async {
                self.popViewController(animated: true)
            }
        } else {
            for subView in navigationBar.subviews {
                if(0 < subView.alpha && subView.alpha < 1) {
                    UIView.animate(withDuration: 0.25, animations: {
                        subView.alpha = 1
                    })
                }
            }
        }

        return false
    }
}

А затем в вашем контроллере представления добавьте функцию делегата:

class BaseVC: UIViewController, BackButtonDelegate {
    func navigationShouldPopOnBackButton() -> Bool {
        if ... {
            return true
        } else {
            return false
        }        
    }
}

Я понял, что мы часто хотим добавить контроллер предупреждений для пользователей, чтобы решить, хотят ли они вернуться. Если да, то вы всегда можете return falseв navigationShouldPopOnBackButton()функции и закрыть контроллер представления, делая что - то вроде этого:

func navigationShouldPopOnBackButton() -> Bool {
     let alert = UIAlertController(title: "Warning",
                                          message: "Do you want to quit?",
                                          preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "Yes", style: .default, handler: { UIAlertAction in self.yes()}))
            alert.addAction(UIAlertAction(title: "No", style: .cancel, handler: { UIAlertAction in self.no()}))
            present(alert, animated: true, completion: nil)
      return false
}

func yes() {
     print("yes")
     DispatchQueue.main.async {
            _ = self.navigationController?.popViewController(animated: true)
        }
}

func no() {
    print("no")       
}
Автор: Lawliet Размещён: 28.02.2017 10:21

1 плюс

Используя переменные target и action, которые вы в настоящее время оставляете «nil», вы сможете связать свои диалоги сохранения так, чтобы они вызывались, когда кнопка «выбрана». Остерегайтесь, это может быть вызвано в странные моменты.

Я согласен в основном с Amagrammer, но я не думаю, что было бы так сложно сделать кнопку со стрелкой на заказ. Я бы просто переименовал кнопку «Назад», сделал снимок экрана, сделал фотошоп нужного размера кнопки, и это было изображение поверх вашей кнопки.

Автор: TahoeWolverine Размещён: 27.07.2009 01:06

1 плюс

Вы можете попытаться получить доступ к элементу правой кнопки NavigationBars и установить его свойство селектора ... вот ссылка на ссылку UIBarButtonItem , и еще одна вещь, если эта работа, которая будет работать именно так, установите правый элемент кнопки панели навигации на пользовательский UIBarButtonItem, который вы создать и установить его селектор ... надеюсь, это поможет

Автор: Daniel Размещён: 25.05.2010 07:58

1 плюс

Для формы, которая требует пользовательского ввода, подобного этой, я бы рекомендовал вызывать ее как «модальную» вместо части вашего стека навигации. Таким образом, они должны позаботиться о бизнесе в форме, затем вы можете проверить ее и отклонить с помощью пользовательской кнопки. Вы даже можете создать навигационную панель, которая будет выглядеть так же, как и остальная часть вашего приложения, но даст вам больше контроля.

Автор: Travis M. Размещён: 08.11.2012 03:40

1 плюс

Чтобы перехватить кнопку «Назад», просто закройте ее прозрачным UIControl и перехватите прикосновения.

@interface MyViewController : UIViewController
{
    UIControl   *backCover;
    BOOL        inhibitBackButtonBOOL;
}
@end

@implementation MyViewController
-(void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    // Cover the back button (cannot do this in viewWillAppear -- too soon)
    if ( backCover == nil ) {
        backCover = [[UIControl alloc] initWithFrame:CGRectMake( 0, 0, 80, 44)];
#if TARGET_IPHONE_SIMULATOR
        // show the cover for testing
        backCover.backgroundColor = [UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:0.15];
#endif
        [backCover addTarget:self action:@selector(backCoverAction) forControlEvents:UIControlEventTouchDown];
        UINavigationBar *navBar = self.navigationController.navigationBar;
        [navBar addSubview:backCover];
    }
}

-(void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    [backCover removeFromSuperview];
    backCover = nil;
}

- (void)backCoverAction
{
    if ( inhibitBackButtonBOOL ) {
        NSLog(@"Back button aborted");
        // notify the user why...
    } else {
        [self.navigationController popViewControllerAnimated:YES]; // "Back"
    }
}
@end
Автор: Jeff Размещён: 19.02.2013 09:46

1 плюс

По крайней мере, в Xcode 5 есть простое и довольно хорошее (не идеальное) решение. В IB перетащите элемент «Панель кнопок» с панели «Утилиты» и поместите его в левой части панели навигации, где будет кнопка «Назад». Установите метку «Назад». У вас будет функциональная кнопка, которую вы можете привязать к вашему IBAction и закрыть свой viewController. Я делаю некоторую работу, а затем запускаю сеанс расслабления, и он работает отлично.

Что не идеально, так это то, что эта кнопка не получает стрелку <и не переносит предыдущий заголовок VC, но я думаю, что этим можно управлять. Для моих целей я установил новую кнопку «Назад» как кнопку «Готово», поэтому ее назначение понятно.

Вы также получите две кнопки «Назад» в навигаторе IB, но для наглядности достаточно легко обозначить их.

введите описание изображения здесь

Автор: Dan Loughney Размещён: 03.04.2014 03:42

1 плюс

стриж

override func viewWillDisappear(animated: Bool) {
    let viewControllers = self.navigationController?.viewControllers!
    if indexOfArray(viewControllers!, searchObject: self) == nil {
        // do something
    }
    super.viewWillDisappear(animated)
}

func indexOfArray(array:[AnyObject], searchObject: AnyObject)-> Int? {
    for (index, value) in enumerate(array) {
        if value as UIViewController == searchObject as UIViewController {
            return index
        }
    }
    return nil
}
Автор: zono Размещён: 28.02.2015 05:22

1 плюс

Этот подход работал для меня (но кнопка «Назад» не будет иметь знак «<»):

- (void)viewDidLoad
{
    [super viewDidLoad];

    UIBarButtonItem* backNavButton = [[UIBarButtonItem alloc] initWithTitle:@"Back"
                                                                      style:UIBarButtonItemStyleBordered
                                                                     target:self
                                                                     action:@selector(backButtonClicked)];
    self.navigationItem.leftBarButtonItem = backNavButton;
}

-(void)backButtonClicked
{
    // Do something...
    AppDelegate* delegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
    [delegate.navController popViewControllerAnimated:YES];
}
Автор: Ivan Размещён: 01.05.2015 09:18

1 плюс

использование isMovingFromParentViewController

override func viewWillDisappear(animated: Bool) {
    super.viewWillDisappear(true)

    if self.isMovingFromParentViewController {
        // current viewController is removed from parent
        // do some work
    }
}
Автор: herrk Размещён: 27.05.2015 03:49

1 плюс

Версия Swift 4 для iOS 11.3:

Это основано на ответе от kgaidis от https://stackoverflow.com/a/34343418/4316579

Я не уверен, когда расширение перестало работать, но на момент написания этой статьи (Swift 4) кажется, что расширение больше не будет выполняться, пока вы не объявите соответствие UINavigationBarDelegate, как описано ниже.

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

extension UINavigationController: UINavigationBarDelegate {
    public func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {

    }
}
Автор: Edward L. Размещён: 30.04.2018 06:37

1 плюс

Ответ от @William, тем не менее, правильный, если пользователь запускает жест пролистывания назад, viewWillDisappearметод вызывается и даже selfне будет в стеке навигации (то есть self.navigationController.viewControllersне будет содержать self), даже если пролистывание не завершена, и контроллер представления фактически не вытолкнут. Таким образом, решение будет:

  1. Отключите жест смахивания назад viewDidAppearи разрешите использование кнопки «Назад» только с помощью:

    if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)])
    {
        self.navigationController.interactivePopGestureRecognizer.enabled = NO;
    }
    
  2. Или просто используйте viewDidDisappearвместо этого следующее:

    - (void)viewDidDisappear:(BOOL)animated
    {
        [super viewDidDisappear:animated];
        if (![self.navigationController.viewControllers containsObject:self])
        {
            // back button was pressed or the the swipe-to-go-back gesture was
            // completed. We know this is true because self is no longer
            // in the navigation stack.
        }
    }
    
Автор: boherna Размещён: 26.01.2016 07:33

0 плюса

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

- (void)viewWillDisappear:(BOOL)animated {
  [super viewWillDisappear:animated];

  if ((self.isMovingFromParentViewController || self.isBeingDismissed)
      && !self.isPoppingProgrammatically) {
    // Do your stuff here
  }
}

Вы должны добавить это свойство к своему контроллеру и установить его в YES, прежде чем выполнить программный запрос:

self.isPoppingProgrammatically = YES;
[self.navigationController popViewControllerAnimated:YES];
Автор: Ferran Maylinch Размещён: 11.05.2015 11:07

0 плюса

Найден новый способ сделать это:

Objective-C

- (void)didMoveToParentViewController:(UIViewController *)parent{
    if (parent == NULL) {
        NSLog(@"Back Pressed");
    }
}

стриж

override func didMoveToParentViewController(parent: UIViewController?) {
    if parent == nil {
        println("Back Pressed")
    }
}
Автор: Ashish Kakkad Размещён: 14.07.2015 04:52

0 плюса

Быстрая версия ответа @ onegray

protocol RequestsNavigationPopVerification {
    var confirmationTitle: String { get }
    var confirmationMessage: String { get }
}

extension RequestsNavigationPopVerification where Self: UIViewController {
    var confirmationTitle: String {
        return "Go back?"
    }

    var confirmationMessage: String {
        return "Are you sure?"
    }
}

final class NavigationController: UINavigationController {

    func navigationBar(navigationBar: UINavigationBar, shouldPopItem item: UINavigationItem) -> Bool {

        guard let requestsPopConfirm = topViewController as? RequestsNavigationPopVerification else {
            popViewControllerAnimated(true)
            return true
        }

        let alertController = UIAlertController(title: requestsPopConfirm.confirmationTitle, message: requestsPopConfirm.confirmationMessage, preferredStyle: .Alert)

        alertController.addAction(UIAlertAction(title: "Cancel", style: .Cancel) { _ in
            dispatch_async(dispatch_get_main_queue(), {
                let dimmed = navigationBar.subviews.flatMap { $0.alpha < 1 ? $0 : nil }
                UIView.animateWithDuration(0.25) {
                    dimmed.forEach { $0.alpha = 1 }
                }
            })
            return
        })

        alertController.addAction(UIAlertAction(title: "Go back", style: .Default) { _ in
            dispatch_async(dispatch_get_main_queue(), {
                self.popViewControllerAnimated(true)
            })
        })

        presentViewController(alertController, animated: true, completion: nil)

        return false
    }
}

Теперь в любом контроллере просто соответствуют RequestsNavigationPopVerificationи это поведение принимается по умолчанию.

Автор: Adam Waite Размещён: 13.06.2016 01:29

0 плюса

Опираясь на предыдущие ответы с UIAlert в Swift5 в асинхронном режиме


protocol NavigationControllerBackButtonDelegate {
    func shouldPopOnBackButtonPress(_ completion: @escaping (Bool) -> ())
}

extension UINavigationController: UINavigationBarDelegate {
    public func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {

        if viewControllers.count < navigationBar.items!.count {
            return true
        }

        // Check if we have a view controller that wants to respond to being popped

        if let viewController = topViewController as? NavigationControllerBackButtonDelegate {

            viewController.shouldPopOnBackButtonPress { shouldPop in
                if (shouldPop) {
                    /// on confirm => pop
                    DispatchQueue.main.async {
                        self.popViewController(animated: true)
                    }
                } else {
                    /// on cancel => do nothing
                }
            }
            /// return false => so navigator will cancel the popBack
            /// until user confirm or cancel
            return false
        }else{
            DispatchQueue.main.async {
                self.popViewController(animated: true)
            }
        }
        return true
    }
}


На вашем контроллере


extension MyController: NavigationControllerBackButtonDelegate {

    func shouldPopOnBackButtonPress(_ completion: @escaping (Bool) -> ()) {

        let msg = "message"

        /// show UIAlert
        alertAttention(msg: msg, actions: [

            .init(title: "Continuer", style: .destructive, handler: { _ in
                completion(true)
            }),
            .init(title: "Annuler", style: .cancel, handler: { _ in
                completion(false)
            })
            ])

    }

}
Автор: brahimm Размещён: 25.07.2019 10:49
Вопросы из категории :
32x32