仿网易新闻首页UI布局
2016-04-14 本文已影响929人
袁俊亮技术博客
title : 仿网易新闻首页UI布局
category : UI
仿网易新闻首页UI布局
标签(空格分隔): UI
[TOC]
源码下载
链接: http://pan.baidu.com/s/1sliRak1 密码: 89jn
效果图(通过Storyboard+代码的方式实现)
仿网易新闻首页UI效果图.png实现代码
JLHomeViewController
继承自UIViewController,主要文件,负责整个效果的逻辑和实现
#import "JLHomeViewController.h"
#import "JLTestViewController.h"
#import "JLHomeLabel.h"
#import "JLConst.h"
@interface JLHomeViewController ()<UIScrollViewDelegate>
/** 标题 */
@property (weak, nonatomic) IBOutlet UIScrollView *titleScrollView;
/** 内容 */
@property (weak, nonatomic) IBOutlet UIScrollView *contentScrollView;
@end
@implementation JLHomeViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.automaticallyAdjustsScrollViewInsets = NO;
// 添加标题
[self setupChildVc];
// 添加子控制器
[self setupTitle];
// 默认显示第0个子控制器的
[self scrollViewDidEndScrollingAnimation:self.contentScrollView];
}
#pragma mark - 初始化
/**
* 添加标题
*/
- (void)setupTitle
{
CGFloat labelW = 100;
CGFloat labelY = 0;
CGFloat labelH = self.titleScrollView.frame.size.height;
for (int i = 0; i < 7; i++) {
JLHomeLabel *label = [[JLHomeLabel alloc] init];
CGFloat labelX = labelW * i;
label.frame = CGRectMake(labelX, labelY, labelW, labelH);
label.text = [self.childViewControllers[i] title];
// 给label添加手势监听事件
[label addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(labelClick:)]];
// 给label绑定tag
label.tag = i;
[self.titleScrollView addSubview:label];
if (i == 0) {
label.scale = 1.0;
}
}
// 设置titleScrollView的contentSize
self.titleScrollView.contentSize = CGSizeMake(labelW * 7, 0);
// 设置contentScrollView的contentSize
// 注意这里的width要用屏幕的宽度,因为这时候加载出来的self.contentScrollView.frame.size.width是XIB的初始宽度600.
// 由于self.view.autoresizingMask的原因使得控制器的view的宽度随着父控制器的frame的改变而改变。所以显示出来以后,self.contentScrollView.frame.size.width为正常的屏幕的宽度
self.contentScrollView.contentSize = CGSizeMake([UIScreen mainScreen].bounds.size.width * 7, 0);
}
/**
* 添加子控制器
*/
- (void)setupChildVc
{
JLTestViewController *testVc0 = [[JLTestViewController alloc] init];
testVc0.title = @"国际";
[self addChildViewController:testVc0];
JLTestViewController *testVc1 = [[JLTestViewController alloc] init];
testVc1.title = @"军事";
[self addChildViewController:testVc1];
JLTestViewController *testVc2 = [[JLTestViewController alloc] init];
testVc2.title = @"社会";
[self addChildViewController:testVc2];
JLTestViewController *testVc3 = [[JLTestViewController alloc] init];
testVc3.title = @"政治";
[self addChildViewController:testVc3];
JLTestViewController *testVc4 = [[JLTestViewController alloc] init];
testVc4.title = @"经济";
[self addChildViewController:testVc4];
JLTestViewController *testVc5 = [[JLTestViewController alloc] init];
testVc5.title = @"体育";
[self addChildViewController:testVc5];
JLTestViewController *testVc6 = [[JLTestViewController alloc] init];
testVc6.title = @"娱乐";
[self addChildViewController:testVc6];
}
#pragma mark - 手势监听事件
/**
* label被点击以后调用
*
* @param tap 手势
*/
- (void)labelClick:(UIGestureRecognizer *)tap
{
// 取出被点击的label的索引
NSInteger index = tap.view.tag;
// 让底部的内容scrollView滚动到对应的位置
CGPoint offset = self.contentScrollView.contentOffset;
offset.x = self.contentScrollView.frame.size.width * index;
[self.contentScrollView setContentOffset:offset animated:YES];
}
#pragma mark - <UIScrollViewDelegate>
/**
* 当scrollView结束了滚动动画以后就会调用这个方法
*
* @param scrollView 当前滚动的scrollView
*/
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
{
CGFloat scrollViewW = scrollView.frame.size.width;
CGFloat scrollViewH = scrollView.frame.size.height;
CGFloat offsetX = scrollView.contentOffset.x;
// 当前位置需要显示的控制器的索引
NSInteger index = offsetX / scrollViewW;
// 让对应的顶部标题居中显示
JLHomeLabel *label = self.titleScrollView.subviews[index];
CGPoint titleOffset = self.titleScrollView.contentOffset;
titleOffset.x = label.center.x - scrollViewW * 0.5;
// 左边超出处理
if (titleOffset.x < 0) titleOffset.x = 0;
// 右边超出处理
CGFloat maxTitleOffsetX = self.titleScrollView.contentSize.width - scrollViewW;
if (titleOffset.x > maxTitleOffsetX) titleOffset.x = maxTitleOffsetX;
[self.titleScrollView setContentOffset:titleOffset animated:YES];
// 让其他label回到最初的状态
for (JLHomeLabel *otherLabel in self.titleScrollView.subviews) {
if (otherLabel != label) otherLabel.scale = 0.0;
}
// 取出需要显示的控制器
UIViewController *willShowVc = self.childViewControllers[index];
// 如果当前位置的控制器的view已经显示过了,就直接返回
if ([willShowVc isViewLoaded]) return;
// 添加控制器的view到contentScrollView中
willShowVc.view.frame = CGRectMake(offsetX, 0, scrollViewW, scrollViewH);
[self.contentScrollView addSubview:willShowVc.view];
}
// 手动拖动scrollView松开后停止减速完毕后才会调用这个方法
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
[self scrollViewDidEndScrollingAnimation:scrollView];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
// 获取比例值
CGFloat scale = scrollView.contentOffset.x / scrollView.frame.size.width;
if (scale < 0 || scale > (self.titleScrollView.subviews.count - 1)) return;
// 获得需要操作的左边label
NSInteger leftIndex = scale;
JLHomeLabel *leftLabel = self.titleScrollView.subviews[leftIndex];
// 获得需要操作的右边的label
NSInteger rightIndex = leftIndex + 1;
JLHomeLabel *rightLabel = (rightIndex == self.titleScrollView.subviews.count) ? nil : self.titleScrollView.subviews[rightIndex];
// 右边比例
CGFloat rightScale = scale - leftIndex;
// 左边比例
CGFloat leftScale = 1 - rightScale;
// 设置label的比例
leftLabel.scale = leftScale;
rightLabel.scale = rightScale;
}
@end
JLTestViewController
继承自UITableViewController,测试文件,用于颜色内容控制器样式
.m文件
#import "JLTestViewController.h"
@interface JLTestViewController ()
@end
static NSString *ID = @"testCell";
@implementation JLTestViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 注册cell
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:ID];
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 50;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
cell.textLabel.text = [NSString stringWithFormat:@"%@ --- %zd",self.title, indexPath.row];
return cell;
}
@end
JLHomeLabel
继承自UILabel,自定义的label,对UILabel的一个简单封装
.h文件
#import <UIKit/UIKit.h>
@interface JLHomeLabel : UILabel
/** label的缩放比例 */
@property (nonatomic, assign) CGFloat scale;
@end
.m文件
#import "JLHomeLabel.h"
#import "JLConst.h"
@implementation JLHomeLabel
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
self.font = [UIFont systemFontOfSize:15];
self.textColor = [UIColor colorWithRed:JLRed green:JLGreen blue:JLBlue alpha:JLAlpha];
self.textAlignment = NSTextAlignmentCenter;
// 使label和用户之间可交互
self.userInteractionEnabled = YES;
}
return self;
}
- (void)setScale:(CGFloat)scale
{
CGFloat red = JLRed + (1 - JLRed) * scale;
CGFloat green = JLGreen + (0 - JLGreen) * scale;
CGFloat blue = JLBlue + (0 - JLBlue) * scale;
self.textColor = [UIColor colorWithRed:red green:green blue:blue alpha:1.0];
// 大小缩放比例
CGFloat transformScale = 1 + scale * 0.2;
self.transform = CGAffineTransformMakeScale(transformScale, transformScale);
}
@end
JLConst
用于存放全局的常量
.h文件
#import <UIKit/UIKit.h>
UIKIT_EXTERN const CGFloat JLRed;
UIKIT_EXTERN const CGFloat JLGreen;
UIKIT_EXTERN const CGFloat JLBlue;
UIKIT_EXTERN const CGFloat JLAlpha;
.m文件
#import <UIKit/UIKit.h>
const CGFloat JLRed = 0;
const CGFloat JLGreen = 0;
const CGFloat JLBlue = 0;
const CGFloat JLAlpha = 1.0;