Как сделать, чтобы упорядочить контроль над UITableViewCell в левой части? - программирование
Подтвердить что ты не робот

Как сделать, чтобы упорядочить контроль над UITableViewCell в левой части?

Я создаю приложение для чтения новостей и хочу, чтобы пользователь мог выбирать категории показа/скрытия новостей (например, главные новости, бизнес, технологии, спорт и т.д.) И изменять их порядок, как приложение BBC для новостей в Android.

Смотрите картинку ниже:

enter image description here

Мой вопрос:

  • Как мне сделать управление переупорядочением в левой части ячейки? (Его положение по умолчанию находится в правой части ячейки в режиме редактирования)
  • У меня есть флажок пользовательский элемент управления. Как мне поместить его в правую часть клетки?
4b9b3361

Ответ 1

Ответ [Если вы не используете какие-либо аксессуары (подробное раскрытие, & c)]

(0) Предполагаю, что у вас установлены ваши таблицы, и .

(1) Это решение работает только в том случае, если ячейки таблиц всегда перетаскиваются. Добавьте это в свой viewDidLoad в файл .m файла Table View.

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self setEditing:YES];
}

(2) Чтобы сделать так, чтобы вы могли изменить порядок своих ячеек, добавьте cell.showsReorderControl = YES; в таблицуView: cellForRowAtIndexPath:.

(3) Убедитесь, что у вас есть tableView: canMoveRowAtIndexPath: и tableView: moveRowAtIndexPath: toIndexPath: методы.

- (BOOL)tableView:(UITableView *)tableview canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
    return YES; 
}

- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
}

(4) Поскольку вам нужен элемент управления переупорядочением слева, мы должны отбирать круг "Удалить", как правило, там, и метод tableView: editingStyleForRowAtIndexPath: делает это.

- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return UITableViewCellEditingStyleNone;
}

(5) Последний шаг, когда происходит волшебство - добавьте tableView: willDisplayCell: forRowAtIndexPath: метод, поиск подкадров соты, сужение его до частного UITableViewCellReorderControl и, наконец, переопределить его.

- (void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    for(UIView* view in cell.subviews)
    {
        if([[[view class] description] isEqualToString:@"UITableViewCellReorderControl"])
        {
            // Creates a new subview the size of the entire cell
            UIView *movedReorderControl = [[UIView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetMaxX(view.frame), CGRectGetMaxY(view.frame))];
            // Adds the reorder control view to our new subview
            [movedReorderControl addSubview:view];
            // Adds our new subview to the cell
            [cell addSubview:movedReorderControl];
            // CGStuff to move it to the left
            CGSize moveLeft = CGSizeMake(movedReorderControl.frame.size.width - view.frame.size.width, movedReorderControl.frame.size.height - view.frame.size.height);
            CGAffineTransform transform = CGAffineTransformIdentity;
            transform = CGAffineTransformTranslate(transform, -moveLeft.width, -moveLeft.height);
            // Performs the transform
            [movedReorderControl setTransform:transform];
        }
    }
}

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

Привет, Хоанг Ван Ха, это мой первый ответ, и я только начал учиться Objective-C месяц назад, поэтому я все еще довольно нул.

Я пытался сделать то же самое с моим приложением и много часов искал, как это сделать. Документация Apple не очень помогает, когда дело доходит до этого. Мне было очень неприятно, когда люди просто ссылались на документацию. Я хотел кричать на них. Надеюсь, мой ответ помог вам.

Много удовольствия для b2Cloud, потому что я использовал некоторые из их кода из этой статьи и адаптировал это для моих ответов.

Ответ 2

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

Я решил общий случай (в ответ на длинное нажатие на любую часть ячейки) в HPReorderTableView, замену замены UITableView. Его можно легко модифицировать, чтобы реагировать на касания на определенных частях ячейки, например, реализовав gestureRecognizer:shouldReceiveTouch: делегата reorderGestureRecognizer.

Ответ 3

Теперь гораздо проще для iOS 9 и более поздних версий

tableView.semanticContentAttribute = .forceRightToLeft

Edit

Как упоминалось Roland, вы должны заметить, что "если вы привязываете подъязыки ячеек с помощью привязок leading и trailing вместо left и right, этот параметр перевернет все."

Ответ 4

Люк Дуберт, получий крутой ответ для iOS 7, его нужно немного изменить:

UIView *cellSubview = cell.subviews[0];
    for(UIView* view in cellSubview.subviews)
    {
        if([[[view class] description] isEqualToString:@"UITableViewCellReorderControl"])
        {

Ответ 5

Это решение не работало для меня в iOS7, поэтому я создал версию для обоих, я надеюсь, что это полезно:

- (void)moveReorderControl:(UITableViewCell *)cell subviewCell:(UIView *)subviewCell
{
    if([[[subviewCell class] description] isEqualToString:@"UITableViewCellReorderControl"]) {
    static int TRANSLATION_REORDER_CONTROL_Y = -20;

        //Code to move the reorder control, you change change it for your code, this works for me
        UIView* resizedGripView = [[UIView alloc] initWithFrame:CGRectMake(0, 0,    CGRectGetMaxX(subviewCell.frame), CGRectGetMaxY(subviewCell.frame))];
        [resizedGripView addSubview:subviewCell];
        [cell addSubview:resizedGripView];

        //  Original transform
        const CGAffineTransform transform = CGAffineTransformMakeTranslation(subviewCell.frame.size.width - cell.frame.size.width, TRANSLATION_REORDER_CONTROL_Y);
        //  Move custom view so the grip top left aligns with the cell top left

        [resizedGripView setTransform:transform];
   }
}

//This method is due to the move cells icons is on right by default, we need to move it.
- (void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (tableView.tag == MEETING_BLOCK_TABLE_TAG) {
        for(UIView* subviewCell in cell.subviews)
        {
            if ([ROCFunctions isIOS7]) {
                if([[[subviewCell class] description] isEqualToString:@"UITableViewCellScrollView"]) {
                    for(UIView* subSubviewCell in subviewCell.subviews) {
                        [self moveReorderControl:cell subviewCell:subSubviewCell];
                    }
                }
            }
            else{
                [self moveReorderControl:cell subviewCell:subviewCell];
            }
        }
    }
}

Ответ 6

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

@implementation CustomTableViewCell

-(void) layoutSubviews {
    [super layoutSubviews];

    // set the frames of the other subviews here if necessary, for example: 
    // self.textLabel.frame = CGRectMake(80, 0, self.textLabel.frame.size.width, self.textLabel.frame.size.height);

    for (UIView* view in self.subviews) {
        if ([[[view class] description] containsString:@"UITableViewCellReorderControl"]) {
            [view setFrame:CGRectMake(20, 0, view.frame.size.width, view.frame.size.height)];
        }
    }
}

@end

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

Выполнение настройки UITableViewReorderControl в файле willDisplayCellAtIndexPath не работает на 100%, первая кнопка переупорядочения не будет корректно размещаться.

Ответ 7

Спасибо всем выше. Вот мое решение. протестировали на iOS7 и iOS9

@implementation StoryPreviewCell
-(void)layoutSubviews{
    [super layoutSubviews];

    //subviews contains first level and second level views. 
    NSMutableArray *subviews = [NSMutableArray array];
    [subviews addObjectsFromArray:self.subviews];
    for (NSInteger i=0; i<self.subviews.count; i++) {
        UIView *firstLevelView = self.subviews[i];
        if(firstLevelView.subviews.count) [subviews addObjectsFromArray:firstLevelView.subviews];
    }

    for(UIView* view in subviews) {
        if([[[view class] description] isEqualToString:@"UITableViewCellReorderControl"]) {
            UIView *reorderControl = view;
            CGFloat leftMoveDistance = 100;//can customize
            CGAffineTransform transform = CGAffineTransformTranslate(CGAffineTransformIdentity, -leftMoveDistance, 0);
            reorderControl.transform = transform;
        }
    }
}
@end

Ответ 8

Для тех, кто использует Xamarin, здесь это мое решение, основанное на ответе @luke-dubert, но заботясь об удалении дополнительных добавленных просмотров при повторном использовании:

В TableViewSource:

public override void WillDisplay(UITableView tableView, UITableViewCell cell, NSIndexPath indexPath)
{
    (cell as GraphBarLineCell)?.SetEditionMode(tableView.Editing);
}

В ячейке:

private UIView _reorderControlContainer;

public void SetEditionMode(bool editing)
    {
        _title.Frame = editing ? TitleFrameForEditing : TitleFrame;

        if (editing)
        {
            var reorderControl = Subviews.FirstOrDefault(x => x.Class.Name.Equals("UITableViewCellReorderControl"));

            if (reorderControl != null)
            {
                _reorderControlContainer?.RemoveFromSuperview();

                // Creates a new subview the size of the entire cell
                _reorderControlContainer = new UIView(new CGRect(0, 0, reorderControl.Frame.GetMaxX(), reorderControl.Frame.GetMaxY()));

                // Adds the reorder control view to our new subview
                _reorderControlContainer.AddSubview(reorderControl);

                // Adds our new subview to the cell
                AddSubview(_reorderControlContainer);

                // CGStuff to move it to the left
                var moveLeft = new CGSize(_reorderControlContainer.Frame.Size.Width - reorderControl.Frame.Size.Width,
                    _reorderControlContainer.Frame.Size.Height - reorderControl.Frame.Size.Height);

                var transform = CGAffineTransform.MakeIdentity();
                transform = CGAffineTransform.Translate(transform, -moveLeft.Width, -moveLeft.Height);
                _reorderControlContainer.Transform = transform;

                // Align the icon with the title
                var icon = reorderControl.Subviews[0];
                icon.Frame = new CGRect(10, 25, icon.Frame.Width, icon.Frame.Height);
            }
        }
    }

Ответ 9

Я протестировал на iOS 12 с использованием swift 4.2 и вместо view.self.description == "UITableViewCellReorderControl" используйте view.self.description.contains("UITableViewCellReorderControl")

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    for view in cell.subviews {
        if view.self.description.contains("UITableViewCellReorderControl") {
            let movedReorderControl = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.maxX, height: view.frame.maxY))
            movedReorderControl.addSubview(view)
            cell.addSubview(movedReorderControl)
            let moveLeft = CGSize(width: movedReorderControl.frame.size.width - view.frame.size.width, height: movedReorderControl.frame.size.height - view.frame.size.height)
            var transform: CGAffineTransform = .identity
            transform = transform.translatedBy(x: -moveLeft.width, y: -moveLeft.height)
            movedReorderControl.transform = transform
        }
    }
}

Ответ 10

Я нашел гораздо более легкое решение, которое не требует абсолютного ручного позиционирования всего и даже работает с анимированными переходами из/в режим редактирования. Должен работать как для iOS6, так и для 7.

Определите эту категорию в UIView где-нибудь:

@interface UIView (ClassSearch)

- (instancetype)subviewOfClassMatching:(NSString*)partialName;

@end

@implementation UIView (ClassSearch)

-(instancetype)subviewOfClassMatching:(NSString *)partialName
{
    if ([[[self class] description] rangeOfString:partialName options:NSCaseInsensitiveSearch].location != NSNotFound) {
        return self;
    }

    for (UIView* v in self.subviews) {
        id match = [v subviewOfClassMatching:partialName];
        if (match) {
            return match;
        }
    }

    return nil;
}

@end

Затем, в вашем подклассе UITableViewCell, переопределите willTransitionToState следующим образом:

-(void)willTransitionToState:(UITableViewCellStateMask)state
{
    [super willTransitionToState:state];

    if (state == UITableViewCellStateShowingEditControlMask) {
        UIView* reorderControl = [self subviewOfClassMatching:@"ReorderControl"];
        UIView* reorderContainer = [[UIView alloc] initWithFrame:self.bounds];
        CGAffineTransform t = CGAffineTransformMakeScale(-1, 1);
        reorderContainer.transform = t;
        [self addSubview:reorderContainer];
        [reorderContainer addSubview:reorderControl];
    }
}

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