iOS & UWP 開発をしているモノトーンです。
Xamarin.iOS with C# での記事です。Objective-C や Swift の場合は読み替えてください。
メッセージアプリやメールアプリのように,Disclosure Indicator を上に寄せる
メールアプリやメッセージアプリでは,このように Disclosure Indicator が上方向に寄せられています。これを AutoLayout でたとえ dynamic type で文字サイズが変わったとしてもある要素の中心に貼り付けます。
Disclosure Indicator は Frame による絶対指定でレイアウトされている
Disclosure Indicator は UIView.Frame
で直接位置が指定されているので,そのまま AutoLayout を反映してしまうとその座標に引っ張られてしまうため,その座標を無効にします。
_accessoryButton.TranslatesAutoresizingMaskIntoConstraints = false;
あとは AutoLayout で配置するだけです。サンプルは,相対時間のラベルの中心 Y座標に固定,相対時間のラベルの右側から +8pt の位置に固定,するです。
以下のコードは MITライセンス にて使用してください。C# でのヘルパークラス例です。
using System; using System.Linq; using UIKit; namespace Mntone.SampleCode.Controllers.Infrastructures { public sealed class TopDisclosureIndicatorHelper : IDisposable { private NSLayoutConstraint _centerYConstraint, _rightConstraint; public TopDisclosureIndicatorHelper() { } public void Dispose() { if (_centerYConstraint != null) { _centerYConstraint.Active = false; _centerYConstraint.Dispose(); _centerYConstraint = null; } if (_rightConstraint != null) { _rightConstraint.Active = false; _rightConstraint.Dispose(); _rightConstraint = null; } GC.SuppressFinalize(this); } public void UpdateConstraints(UIView[] subviews, UIView targetObject) { var accessoryButton = subviews.OfType<UIButton>().FirstOrDefault(); if (accessoryButton != null && targetObject != null) { if (_centerYConstraint != null) { targetObject.RemoveConstraint(_centerYConstraint); _centerYConstraint.Active = false; _centerYConstraint.Dispose(); _centerYConstraint = null; } if (_rightConstraint != null) { targetObject.RemoveConstraint(_rightConstraint); _rightConstraint.Active = false; _rightConstraint.Dispose(); _rightConstraint = null; } accessoryButton.TranslatesAutoresizingMaskIntoConstraints = false; _centerYConstraint = targetObject.CenterYAnchor.ConstraintEqualTo(accessoryButton.CenterYAnchor); _centerYConstraint.Active = true; _rightConstraint = targetObject.RightAnchor.ConstraintEqualTo(accessoryButton.LeftAnchor, -8.0F); _rightConstraint.Active = true; } } } }
使用例
using Foundation; using Mntone.SampleCode.Controllers.Infrastructures; using ReactiveUI; using System; using System.Reactive.Disposables; using UIKit; namespace Mntone.SampleCode.Controllers.Components { public partial class TestTableViewCell : ReactiveTableViewCell<TestViewModel> { public static readonly NSString Key = new NSString(nameof(TestTableViewCell)); private readonly CompositeDisposable _disposables = new CompositeDisposable(); private TopDisclosureIndicatorHelper _helper; public TestTableViewCell(IntPtr handle) : base(handle) { } public override void AwakeFromNib() { base.AwakeFromNib(); _helper = new TopDisclosureIndicatorHelper().AddTo(_yourDisposables); SetNeedsUpdateConstraints(); } public override void UpdateConstraints() { _helper.UpdateConstraints(Subviews, timeLabel); base.UpdateConstraints(); } } }
追記: 2018年5月25日,Constraints 更新処理に記述するように変更しました。SplitViewController 利用時,画面回転にて表示非表示した際に Accessory Button のオブジェクトは毎回作り直されるので,毎回 Accessory Button を探索するように変更し,また制約の解除も適切に行うようにしました。