IOS AutoLayout с Xamarin с использованием ТОЛЬКО кода С# в Visual Studio 2013, без XCode или Interface Builder

Я начал использовать Xamarin, потому что я хотел остаться в среде Visual Studio 2013 и не должен изучать новую среду. В любом случае, я собираюсь вставить свой код контроллера ниже и, надеюсь, кто-то умнее меня (почти наверняка) и может вернуть меня в нужное русло.

Я только что открыл AutoLayout. Мне кажется, что понимание AutoLayout имеет решающее значение для ускорения развития. Тем не менее, я не нахожу много информации для использования AutoLayout с чистым С# в Visual Studio 2013. Возможно, я просто не ищу в нужных местах.

В любом случае, давайте начнем эту новую дискуссию с простого контроллера, который использует AutoLayout TOTALLY на С# без использования каких-либо файлов .nib или Interface Builder. И без использования Xamarin Studio. Просто все сделано в Visual Studio 2013.

Вот требования:

  • Создайте UIViewController, который облегчит реализацию apple iAD.
  • В принципе, мы хотим разместить баннер iAD в нижней части экрана, занимая всю ширину.
  • Мы разместим представление над баннером iAD и заполним оставшуюся часть экрана.
  • Просмотр баннера может время от времени исчезать, если AD не присутствует, поэтому нам нужно обработать это.
  • Нам нужно обращаться, когда устройство вращается для размещения новой ориентации.
  • Нам нужно обрабатывать разные устройства. iPod, iPad, iPhone, версия 4 и 5

    Это должно быть тривиально, но я два дня пробиваю себе голову на клавиатуре, пытаясь заставить это работать. Любые рекомендации, примеры или идеи были бы ВЕЛИКОЙ ПОЛЕЗНОЙ. Помните, мы хотим ТОЛЬКО использовать С# в Visual Studio и вообще не использовать Interface Builder. Вот моя не рабочая попытка:

Используя приведенный ниже код, я заканчиваю тем, что AdBanner отключен от экрана под внутренним представлением. Кроме того, внутренний вид длиннее экрана и только половину ширины экрана. Что здесь происходит? Нужно ли включать функцию AutoLayout? Могу ли я сделать это в коде С# или он скрывается где-то в настройках проекта?

using System;
using MonoTouch.iAd;
using MonoTouch.UIKit;

namespace ADayBDayiOS
{
    public class ADViewController : UIViewController
    {
        private UIView InternalView { get; set; }
        private ADBannerView AdView { get; set; }

        public override void ViewDidLoad()
        {
            base.ViewDidLoad();

            InternalView = new UIView{BackgroundColor=UIColor.Blue}; 

            //This is apple standard ADBannerView
            AdView = new ADBannerView(ADAdType.Banner) {Hidden = true};
            AdView.FailedToReceiveAd += HandleFailedToReceiveAd;
            AdView.AdLoaded += HandleAdLoaded;

            View.BackgroundColor = UIColor.Clear;

            //I'm pretty sure that we need these three lines
            View.TranslatesAutoresizingMaskIntoConstraints = false;
            InternalView.TranslatesAutoresizingMaskIntoConstraints = false;
            AdView.TranslatesAutoresizingMaskIntoConstraints = false;

            View.AddSubview(InternalView);
            View.AddSubview(AdView);

            Resize();
        }

        public override void DidRotate(UIInterfaceOrientation fromInterfaceOrientation)
        {
            base.DidRotate(fromInterfaceOrientation);
            Resize();
        }

        public override void ViewDidAppear(bool animated)
        {
            base.ViewDidAppear(animated);
            Resize();
        }

        private void Resize()
        {
            //Remove all constraints, and reset them...
            View.RemoveConstraints(View.Constraints);

            if (AdView == null || AdView.Hidden)
            {//Fill up the entire screen with our InternalView
                View.AddConstraint(NSLayoutConstraint.Create(InternalView, NSLayoutAttribute.Width, NSLayoutRelation.Equal, View, NSLayoutAttribute.Width, 1, 0));
                View.AddConstraint(NSLayoutConstraint.Create(InternalView, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, View, NSLayoutAttribute.Bottom, 1, 0));
                View.AddConstraint(NSLayoutConstraint.Create(InternalView, NSLayoutAttribute.Top, NSLayoutRelation.Equal, View, NSLayoutAttribute.Top, 1, 0));
            }
            else
            {//Put banner ad at the bottom of the screen and fill the rest of the screen with our InternalView
                View.AddConstraint(NSLayoutConstraint.Create(AdView, NSLayoutAttribute.Width, NSLayoutRelation.Equal, View, NSLayoutAttribute.Width, 1, 0));
                View.AddConstraint(NSLayoutConstraint.Create(InternalView, NSLayoutAttribute.Width, NSLayoutRelation.Equal, View, NSLayoutAttribute.Width, 1, 0));

                View.AddConstraint(NSLayoutConstraint.Create(AdView, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, View, NSLayoutAttribute.Bottom, 1, 0));
                View.AddConstraint(NSLayoutConstraint.Create(InternalView, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, View, NSLayoutAttribute.Bottom, 1, AdView.Bounds.Height));
                View.AddConstraint(NSLayoutConstraint.Create(InternalView, NSLayoutAttribute.Top, NSLayoutRelation.Equal, View, NSLayoutAttribute.Top, 1, 0));
            }
        }

        /// <summary>
        /// Shows the AdView when a new Ad loads
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void HandleAdLoaded(object sender, EventArgs e)
        {
            if (AdView == null)
                return;
            AdView.Hidden = false;
            Resize();
        }

        /// <summary>
        /// Hides the AdView when no ads are available
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void HandleFailedToReceiveAd(object sender, AdErrorEventArgs e)
        {
            if (AdView == null)
                return;
            AdView.Hidden = true;
            Resize();
        }
    }
}

Ответ 1

Создание ограничений в коде для AutoLayout вручную с помощью открытых методов iOS - это утомительный процесс.

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

FluentLayouts

Это сделал автор, создавший MVVMCross, и у вас есть достаточно документация, чтобы вы начали.

Сообщение в блоге

Учебник Youtube Vid

В сущности, вы можете написать такие ограничения, как:

View.AddConstraints(
  button.AtTopOf(View).Plus(vPadding),
  button.AtRightOf(View).Minus(hPadding),
  button.Width().EqualTo(ButtonWidth),

  text.AtLeftOf(View, hPadding),
  text.ToLeftOf(button, hPadding),
  text.WithSameTop(button)
);

Итак, для вашего случая,

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

AutoLayout сам по себе запрашивает позицию X, Y элемента и элемент должен знать желаемый размер. Некоторые элементы управления, такие как кнопки, имеют неявный размер, поэтому вам не нужно явно указывать эту ширину/высоту. Однако такие вещи, как обычная UIView, нет. Поэтому вам также нужно будет указать их размер с ограничениями.

Наконец, наличие такого инструмента, как FluentLayouts, позволяет нам создавать ограничения намного проще, но основы того, что такое AutoLayouts и как использовать его, - это просто общие знания по теме, которые вам действительно могут быть лучше посещая документы для Apple или некоторые обучающие программы, например . Да, это показывает это в XCode, но также объясняет тему, которую мы должны понимать независимо. На этом сайте также есть статьи о ограничениях кода, которые объясняют ничтожество о константах и ​​мультипликаторах и сортах с ограничениями, которые стоит прочитать. После того, как вы поймете понятия и что вы можете с ними сделать, выберите инструмент, как плавные макеты, и ваши требования должны хорошо вписаться.

Ответ 2

Фрэнк Крюгер имеет элегантное решение этой проблемы, о котором вы можете прочитать здесь: http://praeclarum.org/post/45690317491/easy-layout-a-dsl-for-nslayoutconstraint. Код доступен здесь: https://gist.github.com/praeclarum/5175100

Просто добавьте класс в проект iOS, и вы можете написать такой код:

void LayoutWithEase ()
{
    View.ConstrainLayout (() => 
        button.Frame.Width == ButtonWidth &&
        button.Frame.Right == View.Frame.Right - HPadding &&
        button.Frame.Top == View.Frame.Top + VPadding &&

        text.Frame.Left == View.Frame.Left + HPadding &&
        text.Frame.Right == button.Frame.Left - HPadding &&
        text.Frame.Top == button.Frame.Top
    );
}

Ответ 3

Я обнаружил, что следующее работает очень хорошо для простого контроллера, который отображает iAd AdBannerView вместе с обычным представлением. В приведенном ниже коде также вызывается метод "Resize" для всех подзонов, имеющих тип "AdView"

        public override void DidRotate(UIInterfaceOrientation fromInterfaceOrientation)
        {
            Resize();
            base.DidRotate(fromInterfaceOrientation);
        }

        public override void ViewDidAppear(bool animated)
        {
            Resize();
            base.ViewDidAppear(animated);
        }

    private void Resize()
    {
        try
        {
            if (AdBannerView.Hidden)
            {
                InternalView.Frame = new RectangleF(0, 20, View.Bounds.Width, View.Bounds.Height);
                InternalView.Frame = new RectangleF(0, 20, View.Bounds.Width, View.Bounds.Height);
            }
            else
            {
                InternalView.Frame = new RectangleF(0, 20, View.Bounds.Width,
                    View.Bounds.Height - AdBannerView.Bounds.Height);
                AdBannerView.Frame = new RectangleF(0, InternalView.Bounds.Height, View.Bounds.Width,
                    AdBannerView.Bounds.Height);
                InternalView.Frame = new RectangleF(0, 20, View.Bounds.Width,
                    View.Bounds.Height - AdBannerView.Bounds.Height);
                AdBannerView.Frame = new RectangleF(0, InternalView.Bounds.Height, View.Bounds.Width,
                    AdBannerView.Bounds.Height);
            }

            foreach (UIView view in View.Subviews)
            {
                var adView = view as AdView;
                if (adView != null)
                {
                    adView.Resize();
                }
            }
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(ex.ToString());
        }
    }