3

アプリの起動後にa の「上」に表示されるメッセージ ( ) を含む a をUIRefreshControl追加しようとしています。このビューは、が既に更新されており、更新する必要がないことをユーザーに通知します。UIViewstatusMessageViewUITableViewControllerUITableViewController

これが私が達成しようとしていることの内訳です:

アプリが起動され、UITableViewController通常のように表示された後、44 ピクセル下にスクロールして表示されますstatusMessageView(高さ 44 ピクセル)。

statusMessageView2秒間表示されたままになります

UITableViewControllerスクロールを元の位置までアニメートし、効果的に「押し込み」statusMessageViewます。( に似UIRefreshControlていますが、コードでアニメーション化されています)

: これstatusMessageViewは と組み合わせて使用​​されるため、が正常に使用できるUIRefreshControlように、表示後に「消える」必要があります。UIRefreshControl

他のサードパーティの「プルしてリフレッシュ」コントローラーを見てきましたが、私が使用しているという事実のためにそれはやり過ぎだと思いますUIRefreshControl

4

4 に答える 4

2

ここでの他の回答は、UINavigationBar の下にドロップダウンする通知の解決策を提供しているようです。UITableView のスクロールビューに収まるソリューションをまだ探している場合は、カスタム テーブル ヘッダー (セクション ヘッダーではない) をテーブル ビューに追加します。

これを達成するために必要な大まかな手順は次のとおりです。

1. ロード時に最初のヘッダー ビューを作成する

私は通常、(UITableViewController を使用する代わりに) UITableView インスタンス変数を所有する UIViewController サブクラスを使用しますが、どちらのセットアップでもこれを達成できるはずです。tableview セットアップ コード (おそらく viewDidLoad 内) で、backgroundColor、contentInset、separatorStyle などを設定する場所で、ヘッダーになる UILabel を作成します。次に、この UILabel を tableView の tableHeaderView に設定します。もちろん、この「通知セクション」をもう少し複雑なものにしたい場合は、入れ子になった UILabel + 何か他のものを持つ UIView にしてください。次のようなものです:

UILabel *headerLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0f, 0.0f, self.tableView.bounds.size.width, 44.0f)];
headerLabel.backgroundColor = [UIColor clearColor]; // Just in case you have some fancy background/color in your table view
headerLabel.textAlignment = UITextAlignmentCenter;
headerLabel.font = ....
headerLabel.textColor = ....
headerLabel.text = @"You are an awesome user!";
self.tableView.tableHeaderView = headerLabel;

2.テーブルビューを「通常」にロードするように設定します(つまり、ヘッダーを表示しません)

繰り返しますが、viewDidLoad 内で、ロード時にこのヘッダー ビューを非表示にするには、tableview の contentOffset と alwaysBounceVertical を適切に設定する必要があります。ヘッダーの高さに設定された contentOffset は、テーブルビューの y 座標をヘッダーのすぐ下から開始します。alwaysBounceVertical を YES に設定すると、テーブルビューの contentsize が画面サイズよりも小さい場合でも、テーブルビューが正しく動作します。次のようなものです:

self.tableView.contentOffset = (CGPoint){0.0f, 44.0f};
self.tableView.alwaysBounceVertical = YES;

3.スライドを下に追加してスライドします

さて、これを行うにはいくつかの方法があります。viewDidAppear では、最初のアニメーションがテーブルビューを下にスライドする (つまり、contentOffset を {0.0f, 0.0f} に設定する) チェーン UIView アニメーションを作成できます。このアニメーションは 1 秒遅延し、2 番目のアニメーションはテーブルビューを元にスライドします (つまり、設定します)。 contentOffset to {0.0f, 44.0f}) は 2 秒遅れます。または、GCD を使用して、2 つのアニメーションを非同期 + 遅延ブロックとしてスケジュールすることもできます。どちらの方法でも問題ありません (これを実現するには、他におそらく 2 つまたは 3 つの良い方法があります) が、アイデアを理解するために...次のようにアニメーションを連鎖させることができます。

__weak MyCustomViewController *me = self;
[UIView 
    animateWithDuration:0.4f 
    delay:1.0f 
    options:UIViewAnimationOptionAllowUserInteraction 
    animations:^
    { 
        me.tableView.contentOffset = (CGPoint){0.0f, 0.0f}; 
    } 
    completion:^(BOOL finished)
    { 
        if (me.tableView) 
        { 
            [UIView 
                animateWithDuration:0.4f 
                delay:2.0f 
                options:UIViewAnimationOptionAllowUserInteraction 
                animations:^
                { 
                    me.tableView.contentOffset = (CGPoint){0.0f, 44.0f}; 
                } 
                completion:^(BOOL finished)
                { 
                    if (me.tableView) 
                    {  
                        me.tableView.tableHeaderView = nil; // If you want to completely get rid of this notification header
                        me.tableView.contentOffset = (CGPoint){0.0f, 0.0f}; // I'm unsure if this will cause the tableview to jump... if it does, you can animate the headerview away instead of animating the tableview up to hide the header, then setting header to nil and reseting the contentOffset

                        // or

                        me.tableView.tableHeaderView.hidden = YES; // If you want to just hide the header
                    } 
                }]; 
        } 
    }];

サンプルコードは何もテストせずに書いたのですが…ふふふ、多分そのままでは動きません。さらにヘルプが必要な場合は、喜んでお手伝いします。幸運を。

更新: ユーザーがスクロールしてアニメーションをキャンセルできるようにする

テーブルでのユーザー インタラクションがアニメーションに対して何をしたいのかよくわかりません。ユーザーがスクロールを開始したときにアニメーションをキャンセルしたい場合は、GCD を使用します (以下のコードを参照)。しかし、ユーザーのタッチでアニメーションを機能させる他の方法を見ることができるので、探しているものによって異なります。いずれにせよ、ユーザーのタッチが次のスケジュールされたアニメーションを無効にする必要があるとしましょう。次のような 2 つの機能を使用して実現できます。

- (void)scheduleShowHeaderAnimation
{
    __weak MyCustomViewController *me = self;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1.0f * NSEC_PER_SEC), dispatch_get_main_queue(), ^ // Start animating after 1 sec delay
    {
        if (me.tableView) // Make sure the tableview is still around
        {
            if (! me.tableView.tracking &&   // Don't show animation if user has begun to touch contentview
                ! me.tableView.dragging &&   // Don't show animation if user has begun to drag contentview
                ! me.tableView.decelerating) // Don't show animation if dragging happened and scrollview is starting to decelerate
            {
                [UIView
                    animateWithDuration:0.4f
                    delay:0.0f
                    options:UIViewAnimationOptionAllowAnimatedContent // This will make sure user can interact with tableview while animation is going on
                    animations:^
                    {
                        me.tableView.contentOffset = (CGPoint){0.0f, 0.0f};
                    }
                    completion:^(BOOL finished)
                    {
                        [me scheduleHideHeaderAnimation];
                    }];
            }
        }
    });
}

- (void)scheduleHideHeaderAnimation
{
    __weak MyCustomViewController *me = self;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2.0f * NSEC_PER_SEC), dispatch_get_main_queue(), ^ // Start animating after 2 secs delay
    {
        if (me.tableView) // Make sure the tableview is still around
        {
            if (! me.tableView.tracking &&   // Don't show animation if user has begun to touch contentview
                ! me.tableView.dragging &&   // Don't show animation if user has begun to drag contentview
                ! me.tableView.decelerating) // Don't show animation if dragging happened and scrollview is starting to decelerate
            {
                [UIView
                    animateWithDuration:0.4f
                    delay:0.0f
                    options:UIViewAnimationOptionAllowAnimatedContent // This will make sure user can interact with tableview while animation is going on
                    animations:^
                    {
                        me.tableView.contentOffset = (CGPoint){0.0f, 44.0f};
                    }
                    completion:^(BOOL finished)
                    {
                        if (me.tableView)
                        {
                            me.tableView.tableHeaderView = nil; // If you want to completely get rid of this notification header
                            me.tableView.contentOffset = (CGPoint){0.0f, 0.0f}; // I'm unsure if this will cause the tableview to jump... if it does, you can animate the headerview away instead of animating the tableview up to hide the header, then setting header to nil and reseting the contentOffset

                            // or

                            me.tableView.tableHeaderView.hidden = YES; // If you want to just hide the header
                        }
                    }];
            }
        }
    });
}

viewDidAppear で scheduleShowHeaderAnimation を呼び出します。

次に、ユーザーが既にテーブルビューを下にスクロールしているときにヘッダーを非表示にすることをサポートするには、- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerateまたは- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollViewUIScrollViewDelegate のいずれかを実装し、次のようなものを追加します。

if (self.tableView.tableHeaderView != nil)
{
    self.tableView.tableHeaderView = nil;
}

// or

if (self.tableView.tableHeaderView.hidden == NO)
{
    self.tableView.tableHeaderView.hidden = YES;
}

サポートしたいより複雑な操作がある場合、またはアニメーションをユーザーのタッチにさまざまな方法で応答させたい場合は、他の UIScrollViewDelegate メソッドをオーバーライドし、ユーザーがスクロールビュー (親クラスである) との操作を開始したときにオーバーライドする必要がある場合があります。テーブル ビューの)、アニメーションの動作を変更します。

これにより、探しているものに近づきますか?

于 2013-05-30T10:27:05.523 に答える
0

この目的のために、次のライブラリを使用できます。必要に応じて、自動非表示の期間を設定できます。外観をカスタマイズすることもできます。

https://github.com/tciuro/NoticeView

于 2013-05-27T13:28:45.767 に答える
0

これは非常に簡単な方法で実行できます。サブビューを作成して更新コントロールに挿入するだけです。

- (void)viewDidLoad {
    [super viewDidLoad];
    ...
    UIView *smView = [self statusMessageView];
    [self.refreshControl insertSubview: smView atIndex: 0];

    // to show and hide the view inserted in refresh control
    // With this transparent loader color even the middle area is not covered
    // so you can have all the space to show your message
    self.refreshControl.tintColor = [UIColor colorWithWhite:1.0 alpha:0.0];
    [self.refreshControl beginRefreshing];

    [self afterDelay: 2.0  performBlock: ^(){
        [self.refreshControl endRefreshing];
        // this delay is needed to prevent loader animation becoming visible
        // while the refresh control is being hidden
        [self afterDelay: 0.25  performBlock: ^(){
            self.refreshControl.tintColor = nil;
        });
    });
    ...
}

-(void)afterDelay: (float)seconds  performBlock: (void (^)())block  {
    dispatch_time_t popTime =
        dispatch_time(DISPATCH_TIME_NOW, (int64_t)(seconds * NSEC_PER_SEC));
    dispatch_after(popTime, dispatch_get_main_queue(), block);
}

-(UIView)statusMessageView {
    ...
    return view;
}

必要なビュー サイズは 320x43 ピクセルです (これより高い場合は、更新コントロールが非表示になって下部が表示されます)。中央の領域 (約 35 ピクセル) はローダー アニメーションで覆われます (ただし、最初にメッセージを表示するときは異なります)。

そこにアプリケーションのロゴを表示するために UIImageView を使用します (さらに簡単です: hereを参照してください)。

おそらく (ユーザーとして) プルを開始する前にこのメッセージを見ないようにしたいと思います。プルを開始すると、更新が開始される前に更新が不要であることがわかります (このサブビューの高さの約 2 倍をプルダウンすると開始されるため、ユーザーはそこにあるものと更新が必要かどうかを確認する時間があります)。テーブルに未読のアイテム (ツイート、投稿など) がある場合、そのビューに未読アイテムの数を表示できます。

しかし、それは個人的な好みの問題であり、それが行われる方法は、非常に単純な方法であなたが望むものを正確に達成するようです. 私はテストしました、それはすべて動作します。

于 2013-06-01T00:06:29.467 に答える