Вопрос по ios, custom-controls, uitableview – Как сделать, чтобы упорядочить контроль над UITableViewCell в левой части?

17

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

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

enter image description here

Мой вопрос:

How do I make reorder control in left side of cell? (Its default position is in the right side of the cell in edit mode) I have a checkbox custom control. How do I put it in right side of the cell?

Ваш Ответ

9   ответов
12

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

tableView.semanticContentAttribute = .forceRightToLeft

Edit:

КакRoland упомянул, что вы должны заметить, что «если вы выровняете свои ячейки»; подпункты черезleading а такжеtrailing якоря вместоleft а такжеrightэта настройка перевернет все. & quot;

Если вы выровняете свои клетки & apos; подпункты черезleading а такжеtrailing якоря вместоleft а такжеrightэта настройка перевернет все.
4

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

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

Спасибо всем выше. Вот мое решение. протестировали на 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
1

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

@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%, первая кнопка переупорядочения иногда не будет правильно позиционироваться.

23

Вместо охоты наUITableViewCellReorderControl, which is non-public API and might change in the futureЯ рекомендую использоватьUILongPressGestureRecognizer надUITableView и реализовать свою собственную логику переупорядочения.

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

Это правда. Поведение редактирования UITableView не настраивается, и причина в том, что он не был исторически сложившимся, и теперь они не могут его добавить. Вместо этого у них есть более общий UICollectionView, который легко работает в качестве замены для UITableView и позволяет настраивать его поведение.
Обратите внимание, что у этого парня 23,7 тыс. Репутации. Другие ответы не соответствуют действительности и вернутся к вам в будущем. Также помните, что есть веская причина, по которой Apple публикует рекомендации по пользовательскому интерфейсу и старается их придерживаться - пользователи ожидают, что этот элемент управления справа.
-1

Я нашел гораздо более простое решение, которое не требует абсолютного ручного позиционирования чего-либо и даже работает с анимированными переходами из / в режим редактирования. Должно работать как на 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];
    }
}

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

1

Это решение не сработало для меня в 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's top left aligns with the cell's 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];
            }
        }
    }
}
0

Для тех, кто использует 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);
            }
        }
    }
35
Answer [If you're not using any accessories (detail disclosure, &c)]

(0) Я предполагаю, что у вас есть настроенные таблицы, & c;

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

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

(2) Чтобы сделать так, чтобы вы могли изменить порядок своих клеток, добавьтеcell.showsReorderControl = YES; к вашему tableView: 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) Поскольку вы хотите, чтобы элемент управления переупорядочивался слева, мы обычно убираем круг Delete, и это делает метод tableView: editStyleForRowAtIndexPath:.

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

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

Hi Hoang Van Ha, this is my first answer ever, and I only started learning Objective-C a month ago, so I'm still quite a noob.

I've been trying to do the same thing with my app and have been searching for hours how to do it. Apple's documentation isn't very much help when it comes to this. I found it quite frustrating when people would simply link to the documentation. I wanted to yell at them. I hope my answer helped you.

Lots of kudos to b2Cloud because I used some of their code from this article and adapted it for my answers.

У меня была проблема с этим решением, функция willDisplayCell может вызываться несколько раз для одной и той же ячейки, например, когда вы прокручиваете ячейку из окна, а затем внутрь. Когда это происходит и вы снова вызываете преобразование, значок исчезает слева. Они исправили это, вместо того, чтобы использовать преобразования, я установил позицию Y нового представления в фиксированное положение: CGRect newFrame = MoveReorderControl.frame; newFrame.origin.x = -220; MoveReorderControl.frame = newFrame;
Это должен быть принятый ответ. Я искал это некоторое время, и это работало прекрасно. Спасибо Люк.
Я укажу, что проблема, возникающая у @David, также приводит к добавлению нескольких ячеек UIView в ячейку. Это происходит каждый раз, когда TableView прокручивается. Это утечка памяти из-за создания представлений, которые больше не используются, но все равно зависают. Я уже вложил ячейку в подкласс, поэтому добавил свойство для отслеживания созданного представления и повторного использования его в willDisplayCell.
фантастический мистер Люк .... мне нужно как удалить контроль и изменить порядок на левой стороне, это возможно?
Знаете ли вы, как сделать так, чтобы всю ячейку переупорядочивать, чтобы вам не нужно было просто брать маленькую иконку?

Похожие вопросы