YYModel
// 将属性和json关联,将属性和json中对应的key映射
+(NSDictionary *)modelCustomPropertyMapper
{
return @{@"desc" : @"description"};
}
// 将属性和类关联,特别数组、字典
+(NSDictionary *)modelContainerPropertyGenericClass
{
return @{@"photos" : [PhotosModel class]};
}
- (void)setValue:(id)value forUndefinedKey:(NSString *)key
{
if ([key isEqualToString:@"description"]) {
self.desc = value;
}
}
- (id)valueForUndefinedKey:(NSString *)key
{
if ([key isEqualToString:@"description"]) {
return self.desc;
}
return nil;
}
DataBaseManager
#import "DataBaseManager.h"
#import "FMDB.h"
@implementation DataBaseManager
{
// 数据库管理对象
FMDatabase * _fmdb;
}
// 单例方法
+ (instancetype)sharedManager
{
static dispatch_once_t onceToken;
static DataBaseManager * dbManager = nil;
dispatch_once(&onceToken, ^{
if (!dbManager) {
dbManager = [[DataBaseManager alloc] initPrivate];
}
});
return dbManager;
// @synchronized(self) {
// if (!dbManager) {
// dbManager = [[DataBaseManager alloc] initPrivate];
// }
// }
}
// 重写初始化方法
- (instancetype)init
{
// 1. 抛出异常方式
@throw [NSException exceptionWithName:@"DataBaseManager init" reason:@"不能调用init方法" userInfo:nil];
// 2. 断言,判定言论,程序崩溃
// NSAssert(NO, @"DataBaseManager无法调用该方法");
return self;
}
// 重新实现初始化方法
- (instancetype)initPrivate
{
if (self = [super init]) {
[self createDataBase];
}
return self;
}
// 初始化数据库
- (void)createDataBase
{
// 获取沙盒路径下的documents路径
NSArray * documentsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString * dbPath = [[documentsPath firstObject] stringByAppendingPathComponent:@"LimitFree.db"];
NSLog(@"DBPath = %@", dbPath);
if (!_fmdb) {
// 创建数据库管理对象
_fmdb = [[FMDatabase alloc] initWithPath:dbPath];
}
// 打开数据库
if ([_fmdb open]) {
// 创建数据库表
[_fmdb executeUpdate:@"CREATE TABLE if not exists Collection (appId, appName, appImage);"];
}
}
#pragma mark - 增删查
// 判断APPID对应的数据是否存在
- (BOOL)isExistsAppId:(NSString *) appId
{
FMResultSet * rs = [_fmdb executeQuery:@"SELECT * FROM Collection WHERE appId=?", appId];
// 判断结果集是否存在
return [rs next];
}
// 添加数据
- (BOOL)insertAppId:(NSString *) appId appName:(NSString *) appName appImage:(NSString *) appImage
{
// 判断appId在数据库中是否存在
if (![self isExistsAppId:appId]) {
// 如果不存在
BOOL success = [_fmdb executeUpdate:@"INSERT INTO Collection VALUES (?,?,?)", appId, appName, appImage];
return success;
}
return YES;
}
// 获取数据库中所有的记录
- (NSArray *)selectAllApps
{
// 从表Collection中获取所有的数据
FMResultSet * rs = [_fmdb executeQuery:@"SELECT * FROM Collection"];
// 遍历结果集
NSMutableArray * apps = [NSMutableArray array];
while ([rs next]) {
AppDetailModel * detailModel = [[AppDetailModel alloc] init];
detailModel.applicationId = [rs stringForColumn:@"appId"];
detailModel.name = [rs stringForColumn:@"appName"];
detailModel.iconUrl = [rs stringForColumn:@"appImage"];
[apps addObject:detailModel];
}
return [apps copy];
}
// 删除数据库中指定appId数据
- (BOOL)deleteAppId:(NSString *) appId
{
BOOL sucess = [_fmdb executeUpdate:@"DELETE FROM Collection WHERE appId=?", appId];
return sucess;
}
@end
BaseViewController
// 定制导航项的标题
- (void)customNaviItemTitle:(NSString *)title
{
// 定制UINavigationItem的titleView
UILabel * titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 44)];
titleLabel.textAlignment = NSTextAlignmentCenter;
titleLabel.font = [UIFont systemFontOfSize:20];
titleLabel.textColor = [UIColor purpleColor];
// 设置文字
titleLabel.text = title;
// 设置导航项的标题视图
self.navigationItem.titleView = titleLabel;
}
// 定制导航项的按钮
- (void)customTabBarButtonTitle:(NSString *)title image:(NSString *)imageName target:(id)target action:(SEL)selector isLeft:(BOOL)isLeft
{
UIButton * button = [UIButton buttonWithType:UIButtonTypeSystem];
[button setBackgroundImage:[UIImage imageNamed:imageName] forState:UIControlStateNormal];
[button setTitle:title forState:UIControlStateNormal];
[button addTarget:target action:selector forControlEvents:UIControlEventTouchDown];
button.frame = CGRectMake(0, 0, 44, 30);
button.titleLabel.font = [UIFont systemFontOfSize:16];
// 判断是否为左侧按钮
UIBarButtonItem * buttonItem = [[UIBarButtonItem alloc] initWithCustomView:button];
if (isLeft) {
self.navigationItem.leftBarButtonItem = buttonItem;
}
else {
self.navigationItem.rightBarButtonItem = buttonItem;
}
}```
##AppListViewController
// 左侧按钮点击事件响应
-
(void)onLeftClicked:(UIButton *) sender
{
CategoryViewController * categoryVC = [[CategoryViewController alloc] init];
categoryVC.hidesBottomBarWhenPushed = YES;
// 设置分类对应的类
categoryVC.objClass = [self class];// 设置block
__weak typeof(self) weakSelf = self;
categoryVC.block = ^(NSString * cateID) {
weakSelf.categoryID = cateID;
[weakSelf.appListTableView.mj_header beginRefreshing];
};[self.navigationController pushViewController:categoryVC animated:YES];
}
// 创建视图 -
(void)createTableView
{
self.appListTableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, kScreenSize.width, kScreenSize.height - 64)];
// 添加到视图控制器上
[self.view addSubview:self.appListTableView];
// 设置委托和数据源
self.appListTableView.dataSource = self;
self.appListTableView.delegate = self;
// 设置行高
self.appListTableView.rowHeight = 130;// 设置下拉刷新和上拉加载更多
__weak typeof(self) weakSelf = self;
self.appListTableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
weakSelf.currentPage = 1;
[weakSelf requestDataWithPage:1];
}];self.appListTableView.mj_footer = [MJRefreshAutoNormalFooter footerWithRefreshingBlock:^{
weakSelf.currentPage++;
[weakSelf requestDataWithPage:weakSelf.currentPage];
}];// 注册单元格,通过xib方式
[self.appListTableView registerNib:[UINib nibWithNibName:@"AppListCell" bundle:nil] forCellReuseIdentifier:@"AppListCell"];// 添加搜索框
self.searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 200, 40)];
self.appListTableView.tableHeaderView = self.searchBar;
self.searchBar.placeholder = @"百万应用等你来搜索";
self.searchBar.showsCancelButton = YES;
// 设置委托
self.searchBar.delegate = self;
}
// 请求数据 -
(void)requestDataWithPage:(NSInteger) page
{
// 使用弱引用指针
__weak typeof(self) weakSelf = self;
// 拼接URL
NSString * url = [NSString stringWithFormat:self.requestURL, page, self.searchStr ? : @""];
if (self.categoryID) {
// 分类ID不为零时,才追加参数
if (![self.categoryID isEqualToString:@"0"]) {
url = [url stringByAppendingString:[NSString stringWithFormat:@"&cate_id=%@", self.categoryID]];
}
}
// 将URL转换为百分号编码
url = [url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];// 获取NSURLSession单例
NSURLSession * urlSession = [NSURLSession sharedSession];
// 创建数据请求任务
NSURLSessionDataTask * task = [urlSession dataTaskWithURL:[NSURL URLWithString:url] completionHandler:^(NSData * data, NSURLResponse * response, NSError * error) {
// 判断是否请求到数据
if (!error) {
// 解析JSON数据
NSError * err;
NSDictionary * responseDict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&err];
// 判断是否解析成功
if (err == nil) {// 判断是否是首页数据 if (page == 1) { // 清空之前的数据 [weakSelf.appListArray removeAllObjects]; } NSArray * appArray = responseDict[@"applications"]; // 遍历数组将字典装换为模型数据 for (NSDictionary * appDict in appArray) { AppListAppModel * appModel = [[AppListAppModel alloc] init]; [appModel setValuesForKeysWithDictionary:appDict]; [weakSelf.appListArray addObject:appModel]; } // 回到主线程中刷新视图 dispatch_async(dispatch_get_main_queue(), ^{ [weakSelf.appListTableView reloadData]; }); } } else { // 如果请求数据失败,需要将数据回归 if (weakSelf.currentPage > 1) { weakSelf.currentPage --; } } dispatch_async(dispatch_get_main_queue(), ^{ // 停止刷新 [weakSelf.appListTableView.mj_header endRefreshing]; [weakSelf.appListTableView.mj_footer endRefreshing]; });
}];
// 启动任务
[task resume];
}
##CustomTabBarController
// 创建视图控制器
-
(void)createViewControllers
{
// 读取Controllers.plist文件内容
NSString * plistPath = [[NSBundle mainBundle] pathForResource:@"Controllers" ofType:@"plist"];
NSArray * plistArray = [NSArray arrayWithContentsOfFile:plistPath];// 遍历数组,创建视图控制器
NSMutableArray * viewControllers = [NSMutableArray array];
for (NSDictionary * dict in plistArray) {
NSString * title = dict[@"title"];
NSString * iconName = dict[@"iconName"];
NSString * className = dict[@"className"];
// 创建视图控制器
// 1. 类名对应的类
Class class = NSClassFromString(className);
// 2. 创建对象
AppListViewController * appListVC = [[class alloc] init];
appListVC.title = title;// 3. 创建导航控制器 UINavigationController * navi = [[UINavigationController alloc] initWithRootViewController:appListVC]; // 4. 设置UITabBarItem UIImage * normalImage = [[UIImage imageNamed:iconName] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; UIImage * selectedImage = [[UIImage imageNamed:[NSString stringWithFormat:@"%@_press", iconName]] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; navi.tabBarItem = [[UITabBarItem alloc] initWithTitle:title image:normalImage selectedImage:selectedImage]; // 5. 将导航控制器添加到数组中 [viewControllers addObject:navi];
}
// 6. 设置UITabBarController
self.viewControllers = viewControllers;
}
// 自定义UITabBar
- (void)customTabBar
{
// 获取UITabBar
UITabBar * tabBar = self.tabBar;
// 设置背景图片
[tabBar setBackgroundImage:[UIImage imageNamed:@"tabbar_bg"]];
}
// 自定义UINavigationBar
- (void)customNaviBar
{
// 获取所有的导航控制器
NSArray * naviControllers = self.viewControllers;
for (UINavigationController * navi in naviControllers) {
// 获取UINavigationBar
UINavigationBar * naviBar = navi.navigationBar;
// 设置背景图
[naviBar setBackgroundImage:[UIImage imageNamed:@"navigationbar"] forBarMetrics:UIBarMetricsDefault];
}
}
##AppListCell
// 重写appModel的setter方法
-
(void)setAppModel:(AppListAppModel *)appModel
{
// 修改实例变量
_appModel = appModel;// 修改视图
[self.appImageView sd_setImageWithURL:[NSURL URLWithString:_appModel.iconUrl] placeholderImage:[UIImage imageNamed:@"appproduct_appdefault"]];
self.appNameLabel.text = _appModel.name;
self.updateTimeLabel.text = _appModel.updateDate;
// 实现多样式文本需要使用NSAttributedString
// 参数1:多样式的文本
// 参数2:文本样式定义
// 删除符高度,删除符颜色
NSDictionary * attrDict = @{NSStrikethroughStyleAttributeName : @4, NSStrikethroughColorAttributeName : [UIColor orangeColor]};
NSAttributedString * lastPriceAttr = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@"¥%@", _appModel.lastPrice] attributes:attrDict];
self.lastPriceLabel.attributedText = lastPriceAttr;
self.categoryNameLabel.text = _appModel.categoryName;
NSString * countStr = [NSString stringWithFormat:@"分享:%@次 收藏:%@次 下载:%@次", _appModel.shares, _appModel.favorites, _appModel.downloads];
self.countLabel.text = countStr;// 设置星标值
self.starCurrentView.value = [_appModel.starCurrent floatValue];
}
@implementation StarView
{
UIImageView * _foregroudImageView; // 前景图
UIImageView * _backgroudImageView; // 背景图
}
// 重写初始化方法
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
[self createImageViews];
}
return self;
}
// 当使用xib或者Storyboard时,其中视图设置为自定义的类,需要重写该方法。
// 在xib或者Storyboard加载时或者解冻时,会调用此方法创建视图
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder]) {
[self createImageViews];
}
return self;
}
// 创建图片视图
-
(void)createImageViews
{
// 创建背景图
_backgroudImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"StarsBackground"]];
[self addSubview:_backgroudImageView];
// 设置内容模式
_backgroudImageView.contentMode = UIViewContentModeLeft;// 创建前景图
_foregroudImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"StarsForeground"]];
[self addSubview:_foregroudImageView];
// 设置内容模式
_foregroudImageView.contentMode = UIViewContentModeLeft;
// 裁剪
_foregroudImageView.clipsToBounds = YES;
}
// 设置星标视图的值
- (void)setValue:(CGFloat)value
{
_value = value;
if (_value <= 0 || _value > 5) {
return;
}
// 修改前景图的frame
CGRect rect = _backgroudImageView.frame;
rect.size.width *= (value / 5.f);
_foregroudImageView.frame = rect;
}
@end
##SettingViewController
-
(void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
[self customNaviItem];
// 注册单元格
[self.settingCollectionView registerNib:[UINib nibWithNibName:@"SettingCell" bundle:nil] forCellWithReuseIdentifier:@"SettingCell"];
// 设置单元格的大小
UICollectionViewFlowLayout * flowLayout = (UICollectionViewFlowLayout *)self.settingCollectionView.collectionViewLayout;
flowLayout.itemSize = CGSizeMake(57, 57 + 30);
// 设置间距
// 设置行间距
flowLayout.minimumLineSpacing = 20;
// 设置单元格间距
flowLayout.minimumInteritemSpacing = 40;
// 设置内间距
flowLayout.sectionInset = UIEdgeInsetsMake(30, 30, 30, 30);// 设置数据源和委托
self.settingCollectionView.dataSource = self;
self.settingCollectionView.delegate = self;
self.settingCollectionView.backgroundColor = [UIColor whiteColor];// 赋值
self.namesArray = @[@"我的设置", @"我的关注", @"我的账号", @"我的收藏", @"我的下载", @"我的评论", @"我的帮助", @"蚕豆应用"];
self.picsArray = @[@"setting", @"favorite", @"user", @"collect", @"download", @"comment", @"help", @"candou"];// 刷新UICollectionView
[self.settingCollectionView reloadData];
}
pragma mark - UICollectionViewDelegate
-
(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
switch (indexPath.row) {
case 0:
{
// 获取UIStroyboard对象
// 参数1:storyboard的名称,不带后缀名
UIStoryboard * sb = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
// 实例化视图控制器
MySettingViewController * mySettingVC = [sb instantiateViewControllerWithIdentifier:@"MySettingViewController"];
[self.navigationController pushViewController:mySettingVC animated:YES];
}
break;
case 3:
{
CollectionViewController * collectionVC = [[CollectionViewController alloc] init];
[self.navigationController pushViewController:collectionVC animated:YES];
}
break;default: break;
}
}```
CollectionViewController
// 单元格
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
// 复用
CollectionCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"CollectionCell" forIndexPath:indexPath];
// 取出对应的模型
AppDetailModel * model = self.collectionArray[indexPath.row];
cell.appNameLabel.text = model.name;
[cell.appImageView sd_setImageWithURL:[NSURL URLWithString:model.iconUrl] placeholderImage:[UIImage imageNamed:@"appproduct_appdefault"]];
// 判断是否处于编辑状态
if (self.isEditing) {
cell.deleteButton.hidden = NO;
// 动画效果
// 参数1:动画持续时间
// 参数2:动画延迟时间
cell.transform = CGAffineTransformMakeRotation(-0.05);
[UIView animateWithDuration:0.1 delay:0 options:UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse | UIViewAnimationOptionAllowUserInteraction animations:^{
cell.transform = CGAffineTransformMakeRotation(0.05);
} completion:nil];
}
else {
cell.deleteButton.hidden = YES;
}
[cell.deleteButton addTarget:self action:@selector(onDeleteAction:) forControlEvents:UIControlEventTouchUpInside];
return cell;
}
// 删除按钮点击方法
- (void)onDeleteAction:(UIButton *) sender
{
// 找到单元格
CollectionCell * cell = (CollectionCell *)sender.superview.superview;
// 获取单元格对应的indexPath
NSIndexPath * indexPath = [self.collectionView indexPathForCell:cell];
// 先删除单元格还是数据?
// 先删除数据
// 先删除数据库数据
AppDetailModel * detailModel = self.collectionArray[indexPath.row];
[[DataBaseManager sharedManager] deleteAppId:detailModel.applicationId];
// 再删除数据源数据
[self.collectionArray removeObject:detailModel];
// 最后才删除单元格
[self.collectionView deleteItemsAtIndexPaths:@[indexPath]];
// 延迟重新刷新UICollectionView
// 参数1:表示延迟时间
// 参数2:延迟执行操作的队列
// 参数3:执行的操作
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.35 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self.collectionView reloadData];
});
}
AppDetailViewController
// 重写Getter方法
- (CLLocationManager *)locationManager
{
// 1.
if (!_locationManager) {
_locationManager = [[CLLocationManager alloc] init];
// 设置精度
_locationManager.desiredAccuracy = kCLLocationAccuracyBest;
// 设置更新的距离
_locationManager.distanceFilter = 100.0;
// 设置委托
_locationManager.delegate = self;
}
return _locationManager;
}
// 请求定位
- (void)reqeustLocation
{
// 2. 请求用户权限开启定位
// 判断当前APP是否开启定位服务
CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
// 判断是否已授权
if (status == kCLAuthorizationStatusNotDetermined) {
// 请求When-In-Use授权
[self.locationManager requestWhenInUseAuthorization];
}
else if (status == kCLAuthorizationStatusDenied)
{
UIAlertView * alertView = [[UIAlertView alloc] initWithTitle:@"提示" message:@"定位服务已关闭,请在设置中找到爱限免APP,开启定位服务" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil];
[alertView show];
}
else {
// 启动定位服务
[self.locationManager startUpdatingLocation];
}
// 3. 在plist文件中添加对应定位描述信息
}
// 分享按钮点击
- (IBAction)onShareAction:(UIButton *)sender {
//注意:分享到微信好友、微信朋友圈、微信收藏、QQ空间、QQ好友、来往好友、来往朋友圈、易信好友、易信朋友圈、Facebook、Twitter、Instagram等平台需要参考各自的集成方法
// 分享文字
NSString * shortDesc = self.detailModel.description.length > 100 ? [self.detailModel.desc substringToIndex:100] : self.detailModel.desc;
NSString * shareText = [NSString stringWithFormat:@"【%@】%@ %@", self.detailModel.name, shortDesc, self.detailModel.itunesUrl];
UIImage * shareImage = self.appImageView.image;
[UMSocialSnsService presentSnsIconSheetView:self
appKey:nil
shareText:shareText
shareImage:shareImage
shareToSnsNames:nil
delegate:nil];
}
- (IBAction)onFavouriteAction:(UIButton *)sender {
if (self.detailModel) {
// 添加数据到数据库中
BOOL success = [[DataBaseManager sharedManager] insertAppId:self.detailModel.applicationId appName:self.detailModel.name appImage:self.detailModel.iconUrl];
if (success) {
self.favouriteButton.enabled = NO;
[KVNProgress showSuccessWithStatus:@"收藏成功"];
}
else {
[KVNProgress showErrorWithStatus:@"收藏失败"];
}
}
}
- (IBAction)onDownloadAction:(UIButton *)sender {
// 打开一个URL地址
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:self.detailModel.itunesUrl]];
// [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"http://www.baidu.com"]];
// 发送短信
// [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"sms://10086:3123"]];
// 打电话、发邮件、打开某个应用程序
}
// 刷新界面显示数据
- (void)loadDetailData
{
// 判断当前AppId是否在数据库中存在
if ([[DataBaseManager sharedManager] isExistsAppId:self.appId]) {
// 禁用按钮
self.favouriteButton.enabled = NO;
}
[self.appImageView sd_setImageWithURL:[NSURL URLWithString:self.detailModel.iconUrl] placeholderImage:[UIImage imageNamed:@"appproduct_appdefault"]];
self.appNameLabel.text = self.detailModel.name;
self.appInfoLabel.text = [NSString stringWithFormat:@"原价:¥%@ 限免中 文件大小:%@MB", self.detailModel.lastPrice, self.detailModel.fileSize];
self.appCateLabel.text = [NSString stringWithFormat:@"类型:%@ 评分:%@", self.detailModel.categoryName, self.detailModel.starCurrent];
// 滚动图片部分
CGFloat photoHeight = CGRectGetHeight(self.appImageScrollView.frame);
CGFloat photoWidth = photoHeight * 9 / 5;
for (int index = 0; index < self.detailModel.photos.count; index++) {
// 获取模型数据
PhotosModel * photoModel = self.detailModel.photos[index];
UIImageView * imageView = [[UIImageView alloc] initWithFrame:CGRectMake(index*photoWidth, 0, photoWidth, photoHeight)];
[self.appImageScrollView addSubview:imageView];
// 设置图片
[imageView sd_setImageWithURL:[NSURL URLWithString:photoModel.smallUrl] placeholderImage:[UIImage imageNamed:@"appproduct_appdefault"]];
// 开启用户交互
imageView.userInteractionEnabled = YES;
// 设置标记值
imageView.tag = SMALL_PCITURE_BEGIN_TAG + index;
// 100 ~ n
// 添加手势识别器
UITapGestureRecognizer * tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onSmallPicTap:)];
[imageView addGestureRecognizer:tapGesture];
}
// 设置内容尺寸
self.appImageScrollView.contentSize = CGSizeMake(self.detailModel.photos.count * photoWidth, photoHeight);
self.appDescTextView.text = self.detailModel.desc;
}
// 点击手势方法
- (void)onSmallPicTap:(UITapGestureRecognizer *) sender
{
NSInteger selectedIndex = sender.view.tag - SMALL_PCITURE_BEGIN_TAG;
BigPictureViewController * bigPicVC = [[BigPictureViewController alloc] init];
bigPicVC.selectedIndex = selectedIndex;
bigPicVC.photosArray = self.detailModel.photos;
// 设置转场动画样式
bigPicVC.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentViewController:bigPicVC animated:YES completion:nil];
}
#pragma mark - 数据相关
// 请求详情数据
- (void)requestAppDetail
{
[KVNProgress showWithStatus:@"应用详情加载中..." onView:self.view];
__weak typeof(self) weakSelf = self;
// 拼接URL
NSString * url = [NSString stringWithFormat:kDetailUrl, self.appId];
// 请求数据
NSURLSession * session = [NSURLSession sharedSession];
NSURLSessionDataTask * dataTask = [session dataTaskWithURL:[NSURL URLWithString:url] completionHandler:^(NSData * data, NSURLResponse * response, NSError * error) {
// 判断是否请求成功
if (!error) {
weakSelf.detailModel = [AppDetailModel yy_modelWithJSON:data];
// 回到主线程刷新UI
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf loadDetailData];
[KVNProgress showSuccessWithStatus:@"请求成功"];
});
}
else {
[KVNProgress showErrorWithStatus:error.localizedDescription];
}
}];
// 启动任务
[dataTask resume];
}
// 请求附近APP数据
- (void)requestNearApp:(CLLocationCoordinate2D) coordinate
{
__weak typeof(self) weakSelf = self;
// 拼接URL
NSString * url = [NSString stringWithFormat:kNearAppUrl, coordinate.longitude, coordinate.latitude];
// 请求数据
NSURLSession * session = [NSURLSession sharedSession];
// 创建任务
NSURLSessionDataTask * dataTask = [session dataTaskWithURL:[NSURL URLWithString:url] completionHandler:^(NSData * data, NSURLResponse * response, NSError * error) {
if (!error) {
NSDictionary * responseDict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
// 将json数组转换为模型数组
weakSelf.nearAppArray = [NSArray yy_modelArrayWithClass:[NearAppModel class] json:responseDict[@"applications"]];
// 回到主队列刷新UI
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf loadNearApp];
});
}
}];
// 启动任务
[dataTask resume];
}
#pragma mark - CLLocationManagerDelegate
// 授权状态改变回调
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
if (status == kCLAuthorizationStatusDenied) {
NSLog(@"不允许");
}
else {
// 启动定位服务
[manager startUpdatingLocation];
}
}
// 定位改变时回调
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray*)locations
{
if (locations.count > 0) {
// 停止定位服务
[manager stopUpdatingLocation];
// 从数组中取出任意一个位置信息
CLLocation * location = locations.firstObject;
// 根据经纬度请求数据
[self requestNearApp:location.coordinate];
}
}
BigPictureViewController
// 用可视化创建视图,在视图控制器创建[[ alloc] init]时,这些视图不会被创建,只有等到视图将要显示时也就是回调loadView方法时,才会被加载。
// 用AutoLayout布局时,只有在ViewDidAppear时才能获取到视图的正确的frame值
// push/pop、present/dismiss、addObsever/removeObsever、启动timer/关闭timer(视图控制器)
// 代码控制状态栏的显示/隐藏需要设置info.plist,添加【View controller-based status bar appearance】
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.picturesScrollView.delegate = self;
// 添加手势识别器
UITapGestureRecognizer * tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onScrollViewTap:)];
[self.picturesScrollView addGestureRecognizer:tapGesture];
// 通过KVO方式观察self.selectedIndex值的变化
[self addObserver:self forKeyPath:@"selectedIndex" options:NSKeyValueObservingOptionNew context:nil];
}
- (void)onScrollViewTap:(UITapGestureRecognizer *) sender
{
// 判断当前视图是否被隐藏
if ([self.picNumLabel isHidden]) {
for (UIView * view in self.view.subviews) {
if (![view isKindOfClass:[UIScrollView class]]) {
// 除了UIScrollView都显示
view.hidden = NO;
[UIView animateWithDuration:0.3 animations:^{
view.alpha = 1.0;
} completion:^(BOOL finished) {
}];
}
}
// 显示状态栏
[UIApplication sharedApplication].statusBarHidden = NO;
}
else {
// 隐藏视图
for (UIView * view in self.view.subviews) {
if (![view isKindOfClass:[UIScrollView class]]) {
// 除了UIScrollView都显示
[UIView animateWithDuration:0.3 animations:^{
view.alpha = 0.0;
} completion:^(BOOL finished) {
view.hidden = YES;
}];
}
}
// 隐藏状态栏
[UIApplication sharedApplication].statusBarHidden = YES;
}
}
- (void)dealloc
{
// 移除观察者
[self removeObserver:self forKeyPath:@"selectedIndex"];
}
- (IBAction)onSaveAction:(UIButton *)sender {
__weak typeof(self) weakSelf = self;
// 保存图片
// 参数1:要保存的图片
// target-action
// 上下文信息,nil
// 获取当前切换的图片地址
PhotosModel * photosModel = self.photosArray[self.selectedIndex];
// 通过GCD方式创建线程请求数据
// 全局队列:并行队列
// 主队列(UI队列):串行队列
[KVNProgress showWithStatus:@"正在保存图片到相册"];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
// 请求数据
// 同步请求数据
NSData * imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:photosModel.originalUrl]];
// 回到主队列保存数据
dispatch_async(dispatch_get_main_queue(), ^{
UIImage * image = [UIImage imageWithData:imageData];
UIImageWriteToSavedPhotosAlbum(image, weakSelf, @selector(image:didFinishSavingWithError:contextInfo:), nil);
});
});
}
// 保存图片到相册完成时回调方法
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo
{
if (error) {
[KVNProgress showErrorWithStatus:@"保存图片失败,请再次保存"];
}
else {
[KVNProgress showSuccessWithStatus:@"噢耶,成功喽"];
}
}
// 填充UIScrollView数据
- (void)loadPhotos
{
// 图片尺寸
CGFloat imageWidth = CGRectGetWidth(self.picturesScrollView.frame);
CGFloat imageHeight = imageWidth / 1.78;
CGFloat imageY = (CGRectGetHeight(self.picturesScrollView.frame) - imageHeight) / 2;
for (int index = 0; index < self.photosArray.count; index++) {
// 取出数据
PhotosModel * model = self.photosArray[index];
// 创建图片视图
UIImageView * imageView = [[UIImageView alloc] initWithFrame:CGRectMake(index*imageWidth, imageY, imageWidth, imageHeight)];
[self.picturesScrollView addSubview:imageView];
[imageView sd_setImageWithURL:[NSURL URLWithString:model.originalUrl] placeholderImage:[UIImage imageNamed:@"egopv_photo_placeholder"]];
}
// 设置内容尺寸
self.picturesScrollView.contentSize = CGSizeMake(imageWidth * self.photosArray.count, CGRectGetHeight(self.picturesScrollView.frame));
// 按页显示
self.picturesScrollView.pagingEnabled = YES;
// 关闭弹簧效果
self.picturesScrollView.bounces = NO;
// 设置偏移量
self.picturesScrollView.contentOffset = CGPointMake(self.selectedIndex * imageWidth, 0);
// 修改当前图片位置
self.picNumLabel.text = [NSString stringWithFormat:@"%ld Of %ld", self.selectedIndex+1, self.photosArray.count];
}
#pragma mark - UIScrollViewDelegate
// 滚动视图结束减速
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
// 获取当前页数
self.selectedIndex = scrollView.contentOffset.x / scrollView.frame.size.width;
}
#pragma mark - KVO observer方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
NSLog(@"keypath = %@, object = %@, change=%@", keyPath, object, change);
// 修改标题的文字
NSInteger currentIndex = [change[@"new"] integerValue] + 1;
self.picNumLabel.text = [NSString stringWithFormat:@"%ld Of %ld", currentIndex, self.photosArray.count];
}```
##CategoryViewController
-
(void)setObjClass:(Class)objClass
{
_objClass = objClass;NSArray * objClasses = @[[LimitViewController class], [ReduceViewController class], [FreeViewController class], [HotViewController class]];
NSArray * cateNames = @[@"限免", @"降价", @"免费", @"热榜"];
NSArray * categories = @[@"limited", @"down", @"free", @"up"];// 找到对应位置
NSInteger index = [objClasses indexOfObject:_objClass];
self.categoryName = cateNames[index];
self.category = categories[index];// 定制
[self customNaviItem];
} (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
CategoryModel * model = self.categoryArray[indexPath.row];
// 传值
if (self.block) {
self.block(model.categoryId);
}
[self.navigationController popViewControllerAnimated:YES];
}```
LimitViewController
- (instancetype)init
{
if (self = [super init]) {
self.requestURL = kLimitUrl;
}
return self;
}```
##SubjectAppView
import "SubjectAppView.h"
import "StarView.h"
@implementation SubjectAppView
{
UIImageView * _appImageView;
UILabel * _appNameLabel;
UILabel * _commentLabel;
UILabel * _downloadLabel;
StarView * _starView;
}
// 重写初始化方法
(instancetype)init
{
if (self = [super init]) {
[self createViews];
}
return self;
}(instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
[self createViews];
}
return self;
}(instancetype)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder]) {
[self createViews];
}
return self;
}
// 创建视图
// 1. 使用代码实现AutoLayout,需要将视图作为某个视图的子视图
// 2. 将translatesAutoresizingMaskIntoConstraints设为NO
-
(void)createViews
{
_appImageView = [[UIImageView alloc] init];
_appImageView.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_appImageView];_appNameLabel = [[UILabel alloc] init];
[self addSubview:_appNameLabel];_commentLabel = [[UILabel alloc] init];
[self addSubview:_commentLabel];_downloadLabel = [[UILabel alloc] init];
[self addSubview:_downloadLabel];_starView = [[StarView alloc] init];
[self addSubview:_starView];// 将所有视图的关闭停靠模式
for (UIView * view in self.subviews) {
view.translatesAutoresizingMaskIntoConstraints = NO;
}// 建立约束,通过mas_makeConstraints建立约束
// 重新建立约束
// _appImageView mas_remakeConstraints:<#^(MASConstraintMaker *make)block#>
[_appImageView mas_makeConstraints:^(MASConstraintMaker *make) {
// make 表示当前视图建立约束
// 左、上、底部和父视图间距为3
make.left.top.bottom.equalTo(self).offset(3);
// 宽度和高度相等
make.width.equalTo(_appImageView.mas_height);
}];[_appNameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
// 顶部对齐
make.top.equalTo(_appImageView.mas_top);
// 水平间距为5
make.left.equalTo(_appImageView.mas_right).offset(5);
}];[_commentLabel mas_makeConstraints:^(MASConstraintMaker *make) {
// 左对齐
make.left.equalTo(_appNameLabel.mas_left);
// 中心点Y相等
make.centerY.equalTo(_appImageView.mas_centerY);
}];[_downloadLabel mas_makeConstraints:^(MASConstraintMaker *make) {
// 同一水平线
make.centerY.equalTo(_appImageView.mas_centerY);
make.right.equalTo(self.mas_right).offset(-10);
}];[_starView mas_makeConstraints:^(MASConstraintMaker *make) {
// 左对齐
make.left.equalTo(_appNameLabel.mas_left);
// 底部对齐
make.bottom.equalTo(_appImageView.mas_bottom);
// 设置确定的高度和宽度
make.width.equalTo(@65);
make.height.equalTo(@23);
}];
}
// 重写setter方法
-
(void)setAppModel:(Applications *)appModel
{
_appModel = appModel;
[_appImageView sd_setImageWithURL:[NSURL URLWithString:_appModel.iconUrl] placeholderImage:[UIImage imageNamed:@"appproduct_appdefault"]];
_appNameLabel.text = _appModel.name;
// 图文混排
// 创建评论的图文
NSAttributedString * commentAttr = [self createAttrStringWithText:_appModel.ratingOverall image:[UIImage imageNamed:@"topic_Comment"]];_commentLabel.attributedText = commentAttr;
// 创建下载的图文
NSAttributedString * downloadAttr = [self createAttrStringWithText:_appModel.downloads image:[UIImage imageNamed:@"topic_Download"]];
_downloadLabel.attributedText = downloadAttr;// 设置星标数值
_starView.value = [_appModel.starOverall floatValue];
}
// 创建图文混排的富文本
// CoreText.framework 图文混排框架
-
(NSAttributedString *)createAttrStringWithText:(NSString *)text image:(UIImage *) image
{
// NSTextAttachment 可以将图片转换为富文本内容
NSTextAttachment * attachment = [[NSTextAttachment alloc] init];
attachment.image = image;
// 创建通过NSTextAttachment的富文本
// 图片的富文本
NSAttributedString * imageAttr = [NSAttributedString attributedStringWithAttachment:attachment];
// 文字的富文本
NSAttributedString * textAttr = [[NSAttributedString alloc] initWithString:text attributes:@{NSFontAttributeName : [UIFont systemFontOfSize:14]}];NSMutableAttributedString * mulableAttr = [[NSMutableAttributedString alloc] init];
[mulableAttr appendAttributedString:imageAttr];
[mulableAttr appendAttributedString:textAttr];
return [mulableAttr copy];
}
@end
##SubjectCell
// 重写setter方法
-
(void)setModel:(SubjectModel *)model
{
_model = model;
// 装载数据
self.subjectTitleLabel.text = _model.title;
[self.subjectImageView sd_setImageWithURL:[NSURL URLWithString:_model.img] placeholderImage:[UIImage imageNamed:@"topic_TopicImage_Default"]];
[self.descImageView sd_setImageWithURL:[NSURL URLWithString:_model.desc_img] placeholderImage:[UIImage imageNamed:@"topic_Header"]];
self.descTextView.text = _model.desc;// 先移除appsView的所有子视图,循环遍历数组中的对象执行SEL方法
[self.appsView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
// 等价于
// for (UIView * view in self.appsView.subviews) {
// [view removeFromSuperview];
// }// 填充App数据
// 遍历数据
// 记录前一个参照视图
UIView * preView = nil;
for (int index = 0; index < _model.applications.count; index++) {
// 取出数据
Applications * app = _model.applications[index];
// 创建视图
SubjectAppView * appView = [[SubjectAppView alloc] init];
[self.appsView addSubview:appView];
appView.appModel = app;// 建立约束 [appView mas_makeConstraints:^(MASConstraintMaker *make) { // 左对齐 make.left.equalTo(self.appsView.mas_left); // 右对齐 make.right.equalTo(self.appsView.mas_right); // 高度 make.height.equalTo(self.appsView.mas_height).multipliedBy(1/4.f); if (preView == nil) { make.top.equalTo(self.appsView.mas_top); } else { make.top.equalTo(preView.mas_bottom); } }]; // 赋值 preView = appView;
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0 && indexPath.row == 2) {
// 清除图片缓存
[[SDImageCache sharedImageCache] clearDisk];
[[SDImageCache sharedImageCache] clearMemory];
// 清除网络数据
}
}```
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// 设置友盟分享的Appkey
[UMSocialData setAppKey:@"561e6bd3e0f55aa6e5003f5a"];
return YES;
}
#ifdef DEBUG
#define NSLog(...) NSLog(__VA_ARGS__)
#else
#define NSLog(...)
#endif
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSLocationWhenInUseUsageDescription</key>
<string>查找附近的人正在使用的APP</string>