键盘解除后,UITableView无法滚动到底部

时间:2013-04-26 14:56:41

标签: iphone ios objective-c uitableview uiscrollview

我正在尝试创建Any.DO应用的副本。 tableHeaderView是一个“NewTaskCell”视图,其中包含一个UITextField。出于某种原因,在键盘出现后,tableView无法一直滚动到底部。这是我尝试过的:

  1. 更改tableView的框架
  2. 更改tableView的边界
  3. 更改tableView的contentSize
  4. 键盘解除后更新页脚视图
  5. 它必须与键盘或文本字段有关,因为它只在键盘出现时才会发生。

    在下面的动画中,您可以看到如果我单击加号按钮并显示键盘,则tableView无法滚动到底部。之后,如果我点击加号按钮并且显示键盘,那么它可以滚动到底部罚款。

    以下是整个项目的源代码:Any.DO

    这就是我的viewDidLoad方法。

    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        [[self tableView] setAllowsSelection: YES];
        [[self tableView] setShowsVerticalScrollIndicator: NO];
    
        // Make sure there aren't any empty cells showing at the bottom
        // Caused initial error [[self tableView] setTableFooterView: [UIView new]];
    
        // Fixes error at first, until the keyboard shows up
        UIView *footer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 1, 45)];
    footer.backgroundColor = [UIColor clearColor];
    self.tableView.tableFooterView = footer;
    
        // Make the separators look right
        [[self tableView] setSeparatorStyle: UITableViewCellSeparatorStyleSingleLine];
        [[self tableView] setSeparatorColor: [UIColor colorWithWhite: 0.95 alpha: 1]];
    
        UINib *nibTwo = [UINib nibWithNibName: @"TaskCell" bundle: nil];
        [[self tableView] registerNib: nibTwo forCellReuseIdentifier: @"TaskCell"];
    
        // Create the new task cell to go above the tableView
        // --------------------------------------------------
        NewTaskCell *myNewTaskCell = [[NewTaskCell alloc] init];
    
        // Need to access it later to show the keyboard
        [self setTheNewTaskCell: myNewTaskCell];
    
        [[theNewTaskCell view] setFrame: CGRectMake(0, 0, 320, 44)];
        [[[theNewTaskCell reminderButton] layer] setOpacity: 0];
        [[[theNewTaskCell locationButton] layer] setOpacity: 0];
        [[[theNewTaskCell addTaskButton] layer] setOpacity: 0];
    
        // Assign a method for each button
        [[theNewTaskCell reminderButton] addTarget:self action:@selector(addReminder)     forControlEvents: UIControlEventTouchUpInside];
        [[theNewTaskCell locationButton] addTarget:self action:@selector(addLocationReminder) forControlEvents: UIControlEventTouchUpInside];
        [[theNewTaskCell addTaskButton] addTarget:self action:@selector(addTaskToList) forControlEvents: UIControlEventTouchUpInside];
    
        // Separator view
        UIView *separatorView = [[UIView alloc] initWithFrame: CGRectMake(0, 43, 320, 1)];
        [separatorView setBackgroundColor: [UIColor colorWithWhite: 0.5 alpha: 0.2]];
        [[theNewTaskCell view] addSubview: separatorView];
    
        [[self tableView] setTableHeaderView: [theNewTaskCell view]];
        [[self tableView] setContentInset: UIEdgeInsetsMake(-44, 0, 0, 0)];
        // ---------------------------------------------------
        // For Reordering
        [[self tableView] setEditing: YES];
    
        UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget: self action: @selector(longPress:)];
        [longPress setMinimumPressDuration: 0.3];
        [longPress setDelaysTouchesBegan: YES];
    
        [self setLongPressGesture: longPress];
        [[self tableView] addGestureRecognizer: longPress];
    }
    

    单击+按钮时的代码

    -(void)makeNewTask
    {
        // Create the fromPosition and toPosition of the label animation
        CGRect fromPosition;
        CGRect toPosition = CGRectMake(todayDayLabel.frame.origin.x +     todayDayLabel.superview.frame.origin.x, todayDayLabel.frame.origin.y + todayDayLabel.superview.frame.origin.y, todayDayLabel.frame.size.width, todayDayLabel.frame.size.height);
    
        if ([self dayType] == TaskDayTypeToday)
            fromPosition = toPosition;
        else if ([self dayType] == TaskDayTypeTomorrow)
            fromPosition = CGRectMake(tomorrowDayLabel.frame.origin.x + tomorrowDayLabel.superview.frame.origin.x, tomorrowDayLabel.frame.origin.y + tomorrowDayLabel.superview.frame.origin.y, tomorrowDayLabel.frame.size.width, tomorrowDayLabel.frame.size.height);
        else if ([self dayType] == TaskDayTypeUpcoming)
            fromPosition = CGRectMake(upcomingDayLabel.frame.origin.x + upcomingDayLabel.superview.frame.origin.x, upcomingDayLabel.frame.origin.y + upcomingDayLabel.superview.frame.origin.y, upcomingDayLabel.frame.size.width, upcomingDayLabel.frame.size.height);
        else
            fromPosition = CGRectMake(somedayDayLabel.frame.origin.x + somedayDayLabel.superview.frame.origin.x, somedayDayLabel.frame.origin.y + somedayDayLabel.superview.frame.origin.y, somedayDayLabel.frame.size.width, somedayDayLabel.frame.size.height);
        // -------------------------------------------------------------
    
        isLoading = YES;
    
        [[self tableView] reloadData];
    
        // Make sure the scroller doesn't show up on the side
        [[self tableView] setShowsVerticalScrollIndicator: NO];
    
        // Create the label and animate it -------------------------
        UILabel *lbl = [[[[[NSBundle mainBundle] loadNibNamed: @"DayCell" owner: self options:nil] objectAtIndex: 0] subviews] objectAtIndex: 0];
    
        if ([self dayType] == TaskDayTypeToday)
            [lbl setText: @"TODAY"];
        if ([self dayType] == TaskDayTypeTomorrow)
            [lbl setText: @"TOMORROW"];
        if ([self dayType] == TaskDayTypeUpcoming)
            [lbl setText: @"UPCOMING"];
        if ([self dayType] == TaskDayTypeSomeday)
            [lbl setText: @"SOMEDAY"];
    
        [self setTheDayLabel: lbl];
        [theDayLabel setFrame: fromPosition];
    
        [theDayLabel setTranslatesAutoresizingMaskIntoConstraints: YES];
        [[self tableView] addSubview: theDayLabel];
    
        // animate it moving to the right position
        if (!animateContentInset) {
            [[self tableView] setContentInset: UIEdgeInsetsMake(0, 0, 0, 0)];
            [[self tableView] setScrollEnabled: NO];
        }
        else {
            [UIView animateWithDuration: 0.4 delay: 0 options: UIViewAnimationOptionCurveEaseOut animations: ^{
                [[self tableView] setContentInset: UIEdgeInsetsMake(0, 0, 0, 0)];
                [theDayLabel setFrame: toPosition];
            } completion: ^(BOOL done){
                [[self tableView] setScrollEnabled: NO];
            }];
        }
        // ----------------------------------------------------------
        // Create the UIButton to get back to the tableView
        UIButton *backToTableView = [UIButton buttonWithType: UIButtonTypeCustom];
        [backToTableView setFrame: CGRectMake(1, 45, 320, 480)];
        [backToTableView addTarget: self action: @selector(showTableView) forControlEvents: UIControlEventTouchUpInside];
    
        [[self tableView] addSubview: backToTableView];
    
        // Show the keyboard
        [[theNewTaskCell theNewTaskTextField] setDelegate: self];
        //[[theNewTaskCell theNewTaskTextField] becomeFirstResponder];
    }
    

    backToTableView按钮的代码

    -(void)showTableView
    {
        [theDayLabel setHidden: YES];
    
        [[self tableView] setScrollEnabled: YES];
    
        [UIView animateWithDuration: 0.4 animations:^{
            // self.tableView.contentInset = UIEdgeInsetsZero;
            [[self tableView] setContentInset: UIEdgeInsetsMake(-REFRESH_HEADER_HEIGHT, 0, 0, 0)];
    
            // Get the newTaskCell view, then get the textfield from that view
            [[theNewTaskCell theNewTaskTextField] setText: @""];
            [[theNewTaskCell addTaskButton] setAlpha: 0];
            [[theNewTaskCell reminderButton] setAlpha: 0];
            [[theNewTaskCell locationButton] setAlpha: 0];
    
            [[theNewTaskCell theNewTaskTextField] resignFirstResponder];
    
            // Remove the button to go back to the tableView
            for (UIView *v in [[self tableView] subviews]) {
                if (v.frame.origin.x == 1)
                    [v removeFromSuperview];
            }
    
            isLoading = NO;
    
            [[self tableView] reloadData];
        }];
    }
    

    这就是问题所在:

    issue

7 个答案:

答案 0 :(得分:2)

看起来您的UITableView被状态栏偏移了20px。你应该将你的UITableView的高度减少20px并且它将被修复。

答案 1 :(得分:1)

无法理解您在代码中尝试做什么。

但是,看看动画,我想,你只需要将tableview.frame的高度降低10-20分。

这种行为通常出现在内容&框架高度大于可见区域。设置框架高度以匹配可见区域的高度将使您的表格视图滚动。

答案 2 :(得分:1)

我通过将此代码添加到showTableView方法中解决了这个问题:

[[self tableView] setContentInset: UIEdgeInsetsMake(REFRESH_HEADER_HEIGHT, 0, 0, 0)];
[[self tableView] setContentInset: UIEdgeInsetsMake(0, 0, 0, 0)];

答案 3 :(得分:0)

如果该偏移是问题 - 一个选项来解决它,只需为该ViewController进行全屏应用。

这个问题回答你如何 - Is this the right way to make an iPad app full screen?

答案 4 :(得分:0)

对于未来,在 iOS7 上遇到类似问题的人 可以做这样的事情

 [[self tableView] setContentInset: UIEdgeInsetsMake(0, 0, self.bottomLayoutGuide.length, 0)];

topLayoutGuidebottomLayoutGuide是自动布局的一部分,length可供两者使用,它是一个很棒的功能。

答案 5 :(得分:0)

有一个类似的问题并通过删除正在设置TableVC的contentInset的viewWillLayoutSubviews中的代码来解决它:

#include "stdafx.h"
#include <iostream>
#include <vector>

using namespace std;


class Element
{
    public:
        int Center;

        Element(int center)
        {
            Center = center;
        }
};

int main(int)
{
    cout << "Start...\n";
    vector<Element> Elements;

    // add test objects
    Elements.push_back(Element(20));
    Elements.push_back(Element(-370));
    Elements.push_back(Element(128));
    Elements.push_back(Element(77));
    Elements.push_back(Element(-489));
    //cout << "value of a: " << Elements.size() << endl;

    for (vector<Element>::size_type i = 0; i != Elements.size(); i++) {
        cout << "value of a: " << Elements[i].Center << endl;
    }

    return 0;
}

我不明白的是,为什么设置插图,特别是如上图所示不设置底部插件时,会有什么不同?因此,通过不设置它们,可能将插件设置为默认的UIEdgeInsetsZero,它以某种方式解决了这个问题。 Methinks这可能是一个iOS错误。我注意到我只能用32位设备解决这个问题。

答案 6 :(得分:-1)

您可能正在将tableView框架设置为整个屏幕,其中还包括状态栏。 将tableView的高度降低到20像素

[[self tableView] setFrame:CGRectOffset(self.tableView.frame, 0, -20)];

或将框架设置为self.view.frame