В данной статье будет рассмотрен способ модификации UITableView для переноса ячеек таблицы. Вспомним, что Apple нам предлагает тягать ячейки за строго отведенное место:

image

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

Начнем. У нас имеется обычный такой UITableView со свойством
tableView.Editing = true;

Так же, в UITableViewSource у нас есть переопределенный метод
public override bool CanMoveRow (UITableView tableView, NSIndexPath indexPath) => true;

Если запустим приложение — увидим, что с этим свойством мы можем перемещать ячейки таблицы в пределах фрейма самой таблицы.
Спойлер
Кстати, контрол редактирования слева убирается так:
public override UITableViewCellEditingStyle EditingStyleForRow (UITableView tableView, NSIndexPath indexPath) =>UITableViewCellEditingStyle.None;


Теперь зададимся вопросом о том, как сделать так, чтобы строки перемещались не только по тапу на ту маленькую область, отведённую обделённому пользователю, а по всей ячейке.
inb4
Нельзя просто изменить фрейм этого самого контрола, он работает немного иначе, чем можно себе представить, если заинтересует кого-то — расскажу в следующем посте.

Решение проблемы выглядит так:
foreach (var item in cell.Subviews) {
					if (item.Description.Contains ("UITableViewCellReorderControl")) {

						UIView resizedGripView = new UIView(new CGRect(0,0,item.Frame.GetMaxX(),item.Frame.GetMaxY()));
						resizedGripView.AddSubview(item);
						cell.AddSubview(resizedGripView);

			CGSize sizeDifference = new CGSize(resizedGripView.Frame.Size.Width - item.Frame.Size.Width,
							resizedGripView.Frame.Size.Height - item.Frame.Size.Height);

			CGSize transformRatio = new CGSize(resizedGripView.Frame.Size.Width / item.Frame.Size.Width,
							item.Frame.Size.Height / item.Frame.Size.Height);

						CGAffineTransform transform = CGAffineTransform.MakeIdentity();

			transform = CGAffineTransform.Scale(transform, transformRatio.Width, transformRatio.Height);
						nfloat two = new nfloat (2.0);
						nfloat df = -sizeDifference.Width / two;
						nfloat dff = -sizeDifference.Height / two;
						transform = CGAffineTransform.Translate(transform, df,dff);

						resizedGripView.Transform = transform;
						item.Subviews [0].RemoveFromSuperview ();
					}
				}

Далее стояла задача задать стиль ячейки при её переносе. Здесь появился вопрос с тенью, отбрасываемой переносимой ячейкой, эта тень никак не хотела пропадать. После долгих попыток поиска той самой заветной сабвью, всё-таки удалось её отыскать где-то в недрах таблицы, под монотонное стучание бубна.

Делается это в переопределённых методах самой UITableView
UIView wrapperview;

public override UIView[] Subviews {
			get {
				foreach (var item in base.Subviews) {

					if (item.Description.Contains("UITableViewWrapperView")) {
						wrapperview = item;
					}
					if (item.Description.Contains("UIShadowView")) {
						item.Hidden = true;
					}
				}

				return base.Subviews;
			}
		}

		public override void LayoutSubviews ()
		{
			base.LayoutSubviews ();
			foreach (var item in wrapperview.Subviews) {
				if (item.Description.Contains("UIShadowView")) {
					item.Hidden = true;
					item.Layer.ShadowColor = UIColor.White.CGColor;
				}
			}
		}


Этот код подойдет для любой версии IOS, от 6 и выше.

До:
image

После:
image

При переносе ячейка становится прозрачной, поэтому, если вы хотите подкрасить ее или как-то стилизовать — делайте это с помощью cell.BackgroundView.

На мой взгляд, код выглядит достаточно простым и понятным. Скорее всего, для матёрых разработчиков Америки я не открыл, но новичкам будет это полезно знать, да и статей про разработку на Xamarin не так уж и много. Так что, если тема будет актуальна, могу пилить дальше интересные фокусы с интерфейсами Xamarin.IOS/Android и не только.

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

Комментарии (0)