草庐IT

iphone - 为 iOS 设计线程评论系统

coder 2023-07-28 原文

我正在构建一个应用程序来配合我构建的网络应用程序,它具有线程评论系统。

我想知道构建此线程 View 的最佳方法是什么。有没有相对简单的方法来构建 Accordion 样式控件?

我真的很喜欢 Alien Blue 应用程序的处理方式,而且 UI 和 UX 非常流畅:

  • 有人知道这些是如何构建的吗?
  • 将自定义 UIView 添加为 subview 是否是最佳方法?如果是这样,您将如何实现“折叠”样式的功能?

最佳答案

我建议创建一个 UIView 子类来包含每条评论。它应该有一个切换按钮来展开/折叠。在切换打开时,我将框架大小设置为内容的大小(加上任何填充)。它将包含一组子注释,对于每个子注释,您将在展开时将 UIView 子类添加到自身(并在折叠时删除),这些子注释最初会折叠(因此仅显示为切换按钮)。折叠只是相反,删除 subview ,将框架设置为切换按钮的高度(加上填充)

因为每个评论 View 都知道它的大小,所以您可以将整个内容放在一个 UIScrollView 中,并将内容大小设置为评论 View 大小的总和,无论扩展/收缩性质如何都允许滚动。

这个想法的部分实现:

评论.h

#import <Foundation/Foundation.h>

@interface Comment : NSObject {
    NSMutableArray* subComments;
    NSString* comment;
}

@property (nonatomic, retain) NSMutableArray* subComments;
@property (nonatomic, retain) NSString* comment;

@end

评论.m

#import "Comment.h"

@implementation Comment 
@synthesize comment, subComments;

-(id)init
{
    self = [super init];
    if (self)
    {
        subComments = [[NSMutableArray alloc] init];
    }
    return self;
}

@end

评论 View .h

#import <UIKit/UIKit.h>

@interface CommentView : UIView {
    UIButton* toggle;
    NSMutableArray* subComments;
    NSString* commentText;
    UITextView* comment;
    BOOL expanded;
}
@property (strong, nonatomic) NSMutableArray* subComments;
@property (strong, nonatomic) NSString* commentText;


- (void) expand;
- (void) collapse;
- (void) toggleState;

@end

评论 View .m

#import "CommentView.h"


@implementation CommentView
@synthesize subComments,commentText;

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
    }
    [self setBackgroundColor:[UIColor whiteColor]];
    expanded = NO;
    toggle = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
    [toggle setTitle:@"Toggle" forState:UIControlStateNormal];
    [toggle addTarget:self action:@selector(toggleState) forControlEvents:UIControlEventTouchUpInside];
    CGRect curentFrame = self.frame;
    curentFrame.size.height = toggle.frame.size.height + 10;
    [self setFrame:curentFrame];

    curentFrame = toggle.frame;
    curentFrame.origin.y = 5;
    curentFrame.origin.x = 5;
    [toggle setFrame:curentFrame];
    [self addSubview:toggle];
    [self collapse];

    return self;
}

- (void) toggleState
{
    if (expanded)
    {
        [self collapse];
    }
    else
    {
        [self expand];
    }
}

- (void) expand
{
    comment = [[UITextView alloc] init];
    [comment setEditable:NO];
    [comment setText:commentText];
    [self addSubview:comment];
    CGRect curentFrame = comment.frame;
    curentFrame.size.height = comment.contentSize.height;
    curentFrame.origin.x = toggle.frame.size.width + toggle.frame.origin.x + 10;
    curentFrame.size.width = self.frame.size.width - curentFrame.origin.x;
    curentFrame.origin.y = toggle.frame.size.height + toggle.frame.origin.y + 10;
    [comment setFrame:curentFrame];

    curentFrame = self.frame;
    curentFrame.size.height += comment.frame.size.height + 10;
    [self setFrame:curentFrame];
    float height = comment.frame.origin.y + comment.frame.size.height;
    for (NSObject* o in subComments)
    {
        CommentView* subComment = [[CommentView alloc] initWithFrame:CGRectMake(comment.frame.origin.x,height,0,self.frame.size.width)];
        [self addSubview:subComment];
        height += subComment.frame.size.height;
        curentFrame = self.frame;
        curentFrame.size.height += subComment.frame.size.height;
        [self setFrame:curentFrame];
        [self bringSubviewToFront:subComment];
    }
    expanded = YES;
}

- (void) collapse
{
    for (UIView* v in [self subviews])
    {
        [v removeFromSuperview];
    }

    CGRect curentFrame = self.frame;
    curentFrame.size.height = toggle.frame.size.height + 10;
    [self setFrame:curentFrame];

    curentFrame = toggle.frame;
    curentFrame.origin.y = 5;
    curentFrame.origin.x = 5;
    [toggle setFrame:curentFrame];
    [self addSubview:toggle];

    expanded = NO;

}

/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
    // Drawing code
}
*/

@end

ViewContoller.m(使用示例)

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    CommentView* mainCommentView = [[CommentView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];

    Comment* mainComment = [[Comment alloc] init];
    [mainComment setComment: @"Lorem Ipsum 1"];

    Comment* sub1 = [[Comment alloc] init];
    [sub1 setComment: @"Lorem Ipsum 1-1"];
    Comment* sub11 = [[Comment alloc] init];
    [sub11 setComment: @"Lorem Ipsum 1-1-1"];
    [[sub1 subComments] addObject:sub11];

    Comment* sub2 = [[Comment alloc] init];
    [sub2 setComment: @"Lorem Ipsum 1-2"];
    Comment* sub12 = [[Comment alloc] init];
    [sub12 setComment: @"Lorem Ipsum 1-2-1"];
    [[sub2 subComments] addObject:sub12];

    [[mainComment subComments] addObject:sub1];
    [[mainComment subComments] addObject:sub2];

    [mainCommentView setCommentText:[mainComment comment]];
    [mainCommentView setSubComments:[mainComment subComments]];

    self.view = mainCommentView;
}

关于iphone - 为 iOS 设计线程评论系统,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7728412/

有关iphone - 为 iOS 设计线程评论系统的更多相关文章

  1. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  2. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

    我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

  3. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  4. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  5. Ruby 文件 IO 定界符? - 2

    我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

  6. ruby-on-rails - 简单的 Ruby on Rails 问题——如何将评论附加到用户和文章? - 2

    我意识到这可能是一个非常基本的问题,但我现在已经花了几天时间回过头来解决这个问题,但出于某种原因,Google就是没有帮助我。(我认为部分问题在于我是一个初学者,我不知道该问什么......)我也看过O'Reilly的RubyCookbook和RailsAPI,但我仍然停留在这个问题上.我找到了一些关于多态关系的信息,但它似乎不是我需要的(尽管如果我错了请告诉我)。我正在尝试调整MichaelHartl'stutorial创建一个包含用户、文章和评论的博客应用程序(不使用脚手架)。我希望评论既属于用户又属于文章。我的主要问题是:我不知道如何将当前文章的ID放入评论Controller。

  7. 电脑0x0000001A蓝屏错误怎么U盘重装系统教学 - 2

      电脑0x0000001A蓝屏错误怎么U盘重装系统教学分享。有用户电脑开机之后遇到了系统蓝屏的情况。系统蓝屏问题很多时候都是系统bug,只有通过重装系统来进行解决。那么蓝屏问题如何通过U盘重装新系统来解决呢?来看看以下的详细操作方法教学吧。  准备工作:  1、U盘一个(尽量使用8G以上的U盘)。  2、一台正常联网可使用的电脑。  3、ghost或ISO系统镜像文件(Win10系统下载_Win10专业版_windows10正式版下载-系统之家)。  4、在本页面下载U盘启动盘制作工具:系统之家U盘启动工具。  U盘启动盘制作步骤:  注意:制作期间,U盘会被格式化,因此U盘中的重要文件请注

  8. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  9. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

  10. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

随机推荐