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());
}
}