Ui学习--UITableView

news2024/10/5 17:38:07

UI学习

  • UITableView基础
  • UITableView协议
  • UITableView高级协议与单元格
  • 总结


UITableView基础

UITableView作为iOS中的一个控件,用于以表格形式展示数据。例如通讯录好友,朋友圈信息等,都是UITableView的实际运用场景。
首先我们先要加入两个协议:UITableViewDelegate,UITableViewDataSource
在这两个协议中,有必须实现的四个协议方法:

  1. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section :获取每组元素的个数
  2. -(NSInteger) numberOfSectionsInTableView:(UITableView *)tableView:获取每组元素的行数
  3. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath:创建单元格对象函数。

然后我们现在接口文件中添加协议和UITableView对象


#import <UIKit/UIKit.h>

@interface ViewController : UIViewController
<
//实现数据视图的普通协议
//数据视图的普通事件处理
UITableViewDelegate,
//实现数据视图的数据代理协议
//实现数据视图的数据代理
UITableViewDataSource
>
{
    //定义一个数据视图对象
    //数据视图用来显示大量相同格式的大量信息的视图
    //例如:电话通讯录,QQ好友,朋友圈信息
    //相同格式信息内容不同
    UITableView *_tablelView;
}

@end

然后我们在实现部分创建数据视图并实现协议函数


#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    //创建数据视图,传入两个参数
    //参一:数据视图的位置
    //参二:数据视图的风格
    //UITableViewStylePlain:普通风格
    //UITableViewStyleGrouped:分组风格
    _tablelView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
    
    //设置数据视图的代理对象
    _tablelView.delegate = self;
    
    //设置数据视图的数据源对象
    _tablelView.dataSource = self;
    
    [self.view addSubview:_tablelView];
}

//获取每组元素的个数(行数)
//必须要实现的协议函数
//程序在显示数据视图是会调用此函数
//返回值:表示每组元素的个数
//P1:数据视图对象本身
//P2:哪一组需要的行数
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 6;
}

-(NSInteger) numberOfSectionsInTableView:(UITableView *)tableView
{
    return 4;
}


//创建单元格对象函数

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *cellStr = @"cell";
    
    UITableViewCell *cell = [_tablelView dequeueReusableCellWithIdentifier:cellStr];
    
    if (cell == nil) {
        //创建一个单元格对象
        //参一:单元格的样式
        //参二:单元格的复用标记
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellStr];
    }
    NSString *str = [NSString stringWithFormat:@"第%ld组,第%ld行", indexPath.section, indexPath.row];
    
    //将单元格的主文字内容赋值
    cell.textLabel.text = str;
    
    return cell;
}
@end

效果:
在这里插入图片描述


UITableView协议

我们在此处学习如下几个协议:

  1. - (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath:获取单元格高度
  2. -(NSString*) tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section:获取每组头部标题
  3. -(NSString*) tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section:获取每组尾部标题
  4. - (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section:获取头部高度
  5. -(CGFloat) tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section:获取尾部高度

我们省略接口部分,给出实现部分并将上述协议实现:


#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    //创建数据视图对象
    _tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
    
    //设置代理对象
    _tableView.delegate = self;
    //设置数据代理对象
    _tableView.dataSource = self;
    //数据视图显示
    [self.view addSubview:_tableView];
    
    //创建一个可变数组
    _arrayData = [[NSMutableArray alloc] init];
    
    for (int i = 'A'; i <= 'Z'; i++) {
        //定义小数组
        NSMutableArray *arraySmall = [[NSMutableArray alloc] init];
        
        for (int j = 1; j <= 5 ; j++) {
            NSString *str = [NSString stringWithFormat:@"%c%d", i, j];
            
            [arraySmall addObject:str];
        }
        //生成一个二维数组
        [_arrayData addObject:arraySmall];
    }
}

//获取组数
-(NSInteger) numberOfSectionsInTableView:(UITableView *)tableView
{
    return _arrayData.count;
}

//获取每组的元素个数
-(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    NSInteger numRow = [[_arrayData objectAtIndex:section] count];
    
    return numRow;
}

-(UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *str = @"cell";
    
    UITableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier:str];
    
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:str];
    }
    
    cell.textLabel.text = _arrayData[indexPath.section][indexPath.row];
    
    return cell;
}

//获取高度
- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 100;
}

//获取每组头部标题
-(NSString*) tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    return @"哈哈!";
}

//获取每组尾部标题
-(NSString*) tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
{
    return @"尾巴哈哈";
}

//获取头部高度
- (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return 40;
}

//获取尾部高度
-(CGFloat) tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
    return 60;
}

@end

注意:这些协议函数是可选择实现的
效果:
在这里插入图片描述


UITableView高级协议与单元格

我们在此处学习以下高级协议:

  1. - (UITableViewCellEditingStyle) tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath:单元格显示效果协议
  2. - (void) tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath:当手指在单元格上移动时,显示编辑状态
  3. - (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath:选中单元格
  4. -(void) tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath:取消所选单元格,需要在已选择单元格后再选另一单元格后调用。

我们先在接口文件中创建对象,并在SceneDelegate文件里添加导航控制器。

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController
<UITableViewDelegate,
UITableViewDataSource
>

{
    //数据视图
    UITableView *_tableView;
    //数据源
    NSMutableArray* _arrayData;
    
    //添加导航按钮
    UIBarButtonItem *btnEdit;
    UIBarButtonItem *btnFinish;
    UIBarButtonItem *btnDelete;
    //设置编辑状态
    BOOL isEdit;
}
@end

然后,我们在实现部分中,完成对导航栏按钮的创建。并且实现高级协议。


#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    _tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
    
    //自动调整子视图大小
    _tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
    
    //设置代理
    _tableView.delegate = self;
    _tableView.dataSource = self;
    
    //数据视图的头部视图的设定
    _tableView.tableHeaderView = nil;
    //数据视图的尾部视图
    _tableView.tableFooterView = nil;
        
    [self.view addSubview:_tableView];
    
    //初始化数据源数组
    
    _arrayData = [[NSMutableArray alloc] init];
    
    for (int i = 1; i < 20; i++) {
        NSString *str = [NSString stringWithFormat:@"A %d",i];
        
        [_arrayData addObject:str];
    }
    
    //当数据的数据源发生变化时,
    //更新数据视图,重新加载数据
    [_tableView reloadData];
    
    [self createBtn];
}

-(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return _arrayData.count;
}

//默认情况下
-(NSInteger) numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

-(UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *strID = @"ID";

    //尝试获取可以复用的单元格
    //如歌得不到,返回nil
    UITableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier:strID];
    
    //需要显示子标题必须为UITableViewCellStyleSubtitle
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:strID];
    }
    
    //单元格文字赋值
    cell.textLabel.text = [_arrayData objectAtIndex:indexPath.row];
    
    cell.detailTextLabel.text = @"儿子标题";
    
    NSString *str = [NSString stringWithFormat:@"%d.jpg",(indexPath.row % 10 + 1)];
    
    UIImage *image = [UIImage imageNamed:str];
    
    UIImageView *iView = [[UIImageView alloc] initWithImage:image];
    
    cell.imageView.image = image;
    // UIImageView *iView = [[UIImageView alloc] initWithImage:image]
    //设置默认的图标信息
    return cell;
    
   
}

-(void) createBtn
{
    isEdit = NO;
    
    btnEdit = [[UIBarButtonItem alloc] initWithTitle:@"编辑" style:UIBarButtonItemStylePlain target:self action:@selector(pressEdit)];
    btnFinish = [[UIBarButtonItem alloc] initWithTitle:@"完成" style:UIBarButtonItemStylePlain target:self action:@selector(pressFinish)];
    btnDelete = [[UIBarButtonItem alloc] initWithTitle:@"删除" style:UIBarButtonItemStylePlain target:self action:@selector(pressDelete)];
    
    self.navigationItem.rightBarButtonItem = btnEdit;
    
}

-(void) pressEdit
{
    isEdit = YES;
    self.navigationItem.rightBarButtonItem = btnFinish;
    [_tableView setEditing:YES];
    self.navigationItem.leftBarButtonItem = btnDelete;
    
}

-(void) pressFinish
{
    isEdit = NO;
    self.navigationItem.rightBarButtonItem = btnEdit;
    [_tableView setEditing:NO];
    self.navigationItem.leftBarButtonItem = nil;
    
}


- (void)pressDelete {
    // 获取被选中的行的索引集合
    NSArray *selectedRows = [_tableView indexPathsForSelectedRows];
    
    if (selectedRows.count > 0) {
        // 创建一个可变数组,用于存储需要删除的数据
        NSMutableArray *rowsToDelete = [NSMutableArray array];
        
        for (NSIndexPath *indexPath in selectedRows) {
            // 获取需要删除的数据的索引
            NSInteger row = indexPath.row;
            
            // 添加到需要删除的数据数组中
            [rowsToDelete addObject:[NSNumber numberWithInteger:row]];
        }
        
        // 排序需要删除的数据的索引,以确保正确删除
        NSArray *sortedRows = [rowsToDelete sortedArrayUsingSelector:@selector(compare:)];
        
        // 逆序遍历需要删除的数据的索引,从数据源数组中删除对应的数据
        for (NSInteger i = sortedRows.count - 1; i >= 0; i--) {
            NSInteger deleteRow = [sortedRows[i] integerValue];
            [_arrayData removeObjectAtIndex:deleteRow];
        }
        
        // 删除对应的行
        [_tableView deleteRowsAtIndexPaths:selectedRows withRowAnimation:UITableViewRowAnimationAutomatic];
    }
}
//单元格显示效果协议
- (UITableViewCellEditingStyle) tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
    //默认为删除
    //UITableViewCellEditingStyleDelete:删除
    //UITableViewCellEditingStyleInsert:插入
    //UITableViewCellEditingStyleNone:空
    //多选状态UITableViewCellEditingStyleDelete|UITableViewCellEditingStyleInsert
    return UITableViewCellEditingStyleDelete|UITableViewCellEditingStyleInsert;
}

//可以显示编辑状态,当手指在单元格上移动时。
- (void) tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    //删除数据源对应的数据
    [_arrayData removeObjectAtIndex:indexPath.row];
    //数据源更新
    [_tableView reloadData];
    
    
    
    NSLog(@"delete!");
}

//选中时调用
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"选中单元格! %ld, %ld",(long)indexPath.section, (long)indexPath.row);
}

//取消时调用
-(void) tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"取消选中单元格! %ld, %ld",(long)indexPath.section, (long)indexPath.row);
}
@end

我们通过加入一个布尔变量isEdit来判断是否处于编辑状态。在编辑状态下,我们可以对单元格进行插入,删除等操作。
通过使用UITableViewCellEditingStyleDelete|UITableViewCellEditingStyleInsert多选状态,我们可以实现批量删除的操作。
多选后,我们需要重新写编辑状态的删除按钮。即:

- (void)pressDelete {
    // 获取被选中的行的索引集合
    NSArray *selectedRows = [_tableView indexPathsForSelectedRows];
    
    if (selectedRows.count > 0) {
        // 创建一个可变数组,用于存储需要删除的数据
        NSMutableArray *rowsToDelete = [NSMutableArray array];
        
        for (NSIndexPath *indexPath in selectedRows) {
            // 获取需要删除的数据的索引
            NSInteger row = indexPath.row;
            
            // 添加到需要删除的数据数组中
            [rowsToDelete addObject:[NSNumber numberWithInteger:row]];
        }
        
        // 排序需要删除的数据的索引,以确保正确删除
        NSArray *sortedRows = [rowsToDelete sortedArrayUsingSelector:@selector(compare:)];
        
        // 逆序遍历需要删除的数据的索引,从数据源数组中删除对应的数据
        for (NSInteger i = sortedRows.count - 1; i >= 0; i--) {
            NSInteger deleteRow = [sortedRows[i] integerValue];
            [_arrayData removeObjectAtIndex:deleteRow];
        }
        
        // 删除对应的行
        [_tableView deleteRowsAtIndexPaths:selectedRows withRowAnimation:UITableViewRowAnimationAutomatic];
    }
}

效果:
在这里插入图片描述


总结

以上就是对UITableView粗略的学习,还有许多未知的领域等待探索。
下一步,自定义cell和cell的复用!在学习中不断有进步。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1828431.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ARM32开发--电源管理单元

知不足而奋进 望远山而前行 目录 文章目录 前言 学习目标 学习内容 PMU 电源域 VDD/VDDA域 备份域 1.2V域 省电模式 睡眠模式 深度睡眠模式 待机模式 几种模式总结 WFI和WFE指令 案例需求 模式初始化 源码 总结 前言 在嵌入式系统中&#xff0c;有效的电池管…

使用kettle做的数据同步案例

1 mongo同步数据到mysql中 我想把51万8400的计算出来的八字信息&#xff0c;从mongo同步到mysql&#xff0c;看看在mysql中运行会怎么样。 选择mongodb input&#xff0c;这个是在Big Data中。 填写数据库和表 获取到mongodb的字段,获取到mongo的字段&#xff0c;如果某个字段…

Windows10 利用QT搭建SOEM开发环境

文章目录 一. SOEM库简介二. 安装WinPcap三. SOEM(1.4)库安装(1) 编译32位库(2) 编译64位库 四. 运行SOEM示例代码五. WIN10下利用QT构建SOEM开发环境 一. SOEM库简介 SOEM&#xff08;Scalable Open EtherCAT Master 或 Simple Open EtherCAT Master&#xff09;是一个开源的…

SwiftUI 6.0(iOS 18)新容器视图修改器漫谈

概览 本届 WWDC 2024 观影正如火如荼的进行中&#xff0c;一片鸟语花香、枝繁叶茂的苹果树上不时结出几颗令人垂涎欲滴的美味苹果让秃头码农们欲罢不能。 如您所愿&#xff0c;在界面布局“利器” SwiftUI 这根蔓藤也长出不少喜人的果实&#xff0c;其中在 iOS 18.0 中新添加的…

1949年到2021年中国历年稻谷产量统计报告

数据介绍 数据来源于国家统计局&#xff0c;为1949年到2021年我国每年的稻谷产量数据。 2021年&#xff0c;我国稻谷产量为21284.24万吨&#xff0c;比上年增长0.5%。 数据统计单位为&#xff1a;万吨 我国稻谷产量有多少&#xff1f; 2021年&#xff0c;我国稻谷产量为2128…

TIA Portal 博途西门子自动化编程软件下载安装,TIA Portal 提高生产效率!

驱动编程功能则是TIA Portal的又一亮点&#xff0c;它支持各种驱动器的编程和配置&#xff0c;使设备能够精准地执行各种运动控制任务。此外&#xff0c;SCADA&#xff08;监控与数据采集&#xff09;编程功能使得用户可以实时监控生产过程的各项数据&#xff0c;确保生产过程的…

全网爆火的AI语音合成工具-ChatTTS,有人已经拿它赚到了第一桶金,送增强版整合包

上篇分享了如何从0到1搭建一套语音交互系统。 其中&#xff0c;语音合成&#xff08;TTS&#xff09;是提升用户体验的关键所在。 不得不说&#xff0c;AI 语音界人才辈出&#xff0c;从之前的Bert-Sovit&#xff0c;到GPT-Sovits&#xff0c;再到最近一周狂揽了 1w Star 的C…

在顺序表中使用顺序查找法查找某个关键字

//顺序表中顺序查找(SeqSearch) #include<stdio.h> #include<stdlib.h> #define MAX 100 #include<assert.h> typedef struct {int data[MAX];int length; }SeqList; int SeqSearch(SeqList* S, int key)//key为要查找的值 {printf("关键字序列&#xf…

11.泛型、trait和生命周期(上)

标题 一、泛型数据的引入二、改写为泛型函数三、结构体/枚举中的泛型定义四、方法定义中的泛型 一、泛型数据的引入 下面是两个函数&#xff0c;分别用来取得整型和符号型vector中的最大值 use std::fs::File;fn get_max_float_value_from_vector(src: &[f64]) -> f64…

转让注册地址在北京的无区域投资管理集团公司

公司名称中不带省市地域&#xff0c;或是公司名称没有行业表述的公司&#xff0c;都是要在工商总局进行核名的&#xff0c;我们简称为总局无区域核名公司&#xff0c;此类公司的注册须经总局局批准&#xff0c;名称可以不带省市地域、行业特点&#xff0c;现在公司名称新核准已…

LeetCode206-反转链表

题目 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 代码 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val val; }* …

【网络编程】进程间的通信

进程间通信意味着两个不同进程间交换数据&#xff0c;操作系统中应提供两个进程可以同时访问内存空间。 管道实现进程间通信 管道不属于进程资源&#xff0c;与套接字一样属于操作系统。两个进程通过操作系统提供内存空间进行通信 #include<unistd.h> int pipe(int fil…

高考志愿填报,如何选择大学专业?

选择大学专业是一件需要谨慎的事情&#xff0c;需要综合考虑各个因素。大学专业和将来的就业方向是一致的&#xff0c;选专业实际就是在选职业&#xff0c;选自己未来几十年的职业生活。如何去选择大学专业&#xff0c;建议从个人兴趣&#xff0c;个人优势能力&#xff0c;职业…

大家来决定:python-office运行时的提示信息,要不要删除?

​ 大家好&#xff0c;这里是程序员晚枫&#xff0c;今天想请大家投票决定一下&#xff1a;运行python-office时的下面这种中文提示信息&#xff0c;要不要全部都取消了&#xff1f;&#x1f447; 为什么加这个提示&#xff1f; 我是在2022年发布的这个开源项目&#xff0c;并…

Ctrl+Back(回退键)快捷键失效,导致IDEA不能删除多个字符

CtrlBackspace快捷键差不多失效了2年&#xff0c;因为没怎么用笔记本了&#xff0c;所以就没管。这阵子开始用了&#xff0c;在Idea里面不能通过CtrlBack的方式删除&#xff0c;只能一个个字符删除&#xff0c;真的难受。 后面尝试退出一些软件&#xff0c;停止一些服务&#x…

Bio-Info每日一题:Rosalind-07-Mendel‘s First Law(孟德尔第一定律 python实现)

&#x1f389; 进入生物信息学的世界&#xff0c;与Rosalind一起探索吧&#xff01;&#x1f9ec; Rosalind是一个在线平台&#xff0c;专为学习和实践生物信息学而设计。该平台提供了一系列循序渐进的编程挑战&#xff0c;帮助用户从基础到高级掌握生物信息学知识。无论你是初…

5000天后的世界

为何可以预见未来 1993年&#xff0c;在互联网的黎明时代&#xff0c;凯文凯利创办了《连线》杂志。他曾经采访过以比尔盖茨、史蒂夫乔布斯、杰夫贝佐斯为代表的一众风云创业家。《连线》杂志是全球发行的世界著名杂志&#xff0c;一直致力于报道科学技术带来的经济、社会变革…

特种设备观光车司机N2精选模拟试题

11、过电压继电器的返回电压与动作电压之比称为过电压继电器的返回系数。(√) 12、部门规章和地方政府规章都属于行政规章。(√) 13、在没有障碍时&#xff0c;倒车的车速应快一些&#xff0c;以免防碍交通。()(x) 14、场(厂)内专用机动车辆的安全运行&#xff0c;由使用单位…

LabVIEW开发中的常见通讯协议详解

介绍LabVIEW开发中常见的通讯协议&#xff0c;包括RS-232、RS-485、I2C、SPI、CAN、Ethernet、Modbus和GPIB等。通过对各协议的具体内容、特点、使用范围及注意事项进行全面解析&#xff0c;帮助开发者选择合适的通讯协议&#xff0c;提高系统性能和可靠性。 1. RS-232 内容&a…

打造成功的人力RPO项目:赢得市场赚取利润

人力资源外包(RPO)项目是当今企业在招聘和人才管理方面越来越倾向的选择。想要通过人力RPO项目赚钱&#xff0c;以下是一些关键的策略和步骤&#xff0c;帮助您进入这个市场并取得成功。 1. 建立专业的人力RPO服务 首先&#xff0c;要想在人力RPO项目中赚钱&#xff0c;必须建立…