1 使用UIDynamicAnimator对集合视图进行布局

1.1 问题

UIKit Dynamic动力模型一个非常有趣的用途就是影响集合视图的布局,可以给集合视图的布局添加各种动力行为,使其产生丰富多彩的效果,本案例使用UIDynamicAnimator对集合视图进行布局,实现一个弹性列表,如图-1所示:

图-1

1.2 方案

首先创建一个SingleViewApplication项目,给UIColor类创建一个分类UIColor+RandomColor,提供一个产生随机颜色的静态方法randomColor。

其次创建一个自定义布局类TRCollectionViewSpringCellLayout继承至UICollectionViewFlowLayout,该类有一个UIDynamicAnimator类型的属性animator。重写prepareLayout方法(该方法在布局开始前自动调用),在该方法中使用initWithCollectionViewLayout:创建animator对象,然后给每个items都添加UIAttachmentBehavior行为。

然后实现layoutAttributesForElementsInRect: 和 layoutAttributesForItemAtIndexPath: 这两个方法,程序运行的时候会通过调用它们来询问 collectionView每一个 item 的布局信息。

再实现shouldInvalidateLayoutForBoundsChange:,该方法会在集合视图的 bounds发生改变的时候被调用,根据最新的contentOffset 调整animator中behaviors 的参数,在重新调整之后该方法返回NO。

最后在TRViewController的viewDidLoad方法中使用TRCollectionViewSpringCellLayout对象创建集合视图collectionView,并且实现集合视图的协议方法给集合视图加载数据。

1.3 步骤

实现此案例需要按照如下步骤进行。

步骤一:创建UIColor分类

首先创建一个SingleViewApplication项目,给UIColor类创建一个分类UIColor+RandomColor,提供一个产生随机颜色的静态方法randomColor,代码如下所示:

 
  1. + (UIColor *)randomColor
  2. {
  3. CGFloat red = arc4random() % 256 / 256.0;
  4. CGFloat green = arc4random() % 256 / 256.0;
  5. CGFloat blue = arc4random() % 256 / 256.0;
  6. return [UIColor colorWithRed:red green:green blue:blue alpha:1.0];
  7. }

步骤二:创建自定义布局类TRCollectionViewSpringCellLayout

首先创建一个自定义布局类TRCollectionViewSpringCellLayout继承至UICollectionViewFlowLayout,该类有一个UIDynamicAnimator类型的属性animator,代码如下所示:

  1. @interface TRCollectionViewSpringCellLayout ()
  2. @property (strong, nonatomic) UIDynamicAnimator *animator;
  3. @end

其次重写prepareLayout方法(该方法在布局开始前自动调用),在该方法中使用initWithCollectionViewLayout:创建animator对象,然后给每个items都添加UIAttachmentBehavior行为,代码如下所示:

 
  1. //布局前的准备,布局开始前自动调用
  2. - (void)prepareLayout
  3. {
  4. if(!self.animator){
  5. //通过集合视图布局创建animator对象
  6. self.animator = [[UIDynamicAnimator alloc]initWithCollectionViewLayout:self];
  7. CGSize contentSize = self.collectionViewContentSize;
  8. //获取所有的items
  9. NSArray *items = [super layoutAttributesForElementsInRect:CGRectMake(0, 0, contentSize.width, contentSize.height)];
  10. //给每个一Cell创建UIAttachmentBehavior
  11. for (UICollectionViewLayoutAttributes *attributes in items) {
  12. UIAttachmentBehavior *spring = [[UIAttachmentBehavior alloc]initWithItem:attributes attachedToAnchor:attributes.center];
  13. spring.damping = 0.6;
  14. spring.frequency = 0.8;
  15. [self.animator addBehavior:spring];
  16. }
  17. }
  18. }

然后实现layoutAttributesForElementsInRect: 和 layoutAttributesForItemAtIndexPath: 这两个方法,程序运行的时候会通过调用它们来询问 collectionView每一个 item 的布局信息,代码如下所示:

 
  1. //在集合视图滚动时会自动调用,返回所有cell的属性,并传递可见的矩形区域
  2. - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
  3. {
  4. //当collectionView需要layout信息时由animator提供
  5. return [self.animator itemsInRect:rect];
  6. }
  7. - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
  8. {
  9. return [self.animator layoutAttributesForCellAtIndexPath:indexPath];
  10. }

最后实现shouldInvalidateLayoutForBoundsChange:,该方法会在集合视图的 bounds发生改变的时候被调用,根据最新的contentOffset 调整animator中behaviors 的参数,在重新调整之后该方法返回NO,代码如下所示:

 
  1. //当bounds发生变化时,调用方法,为不同的Cell改变不同的锚点
  2. - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
  3. {
  4. UIScrollView *scrollView = self.collectionView;
  5. //获取滚动的距离
  6. CGFloat scrollDelta = newBounds.origin.y - scrollView.bounds.origin.y;
  7. //手指所在的位置
  8. CGPoint touchLocation = [scrollView.panGestureRecognizer locationInView:scrollView];
  9. //计算和改动每一个Cell的锚点
  10. for (UIAttachmentBehavior *spring in self.animator.behaviors) {
  11. UICollectionViewLayoutAttributes *item = [spring.items firstObject];
  12. CGPoint center = item.center;
  13. CGPoint anchorPoint = spring.anchorPoint;
  14. CGFloat distance = fabsf(touchLocation.y - anchorPoint.y);
  15. CGFloat scrollResistance = distance / 600;
  16. center.y += (scrollDelta>0)?MIN(scrollDelta, scrollDelta * scrollResistance):MAX(scrollDelta, scrollDelta * scrollResistance);
  17. item.center = center;
  18. //当item处于动画中时,如果对象主动修改了位置信息,需要更新动画
  19. [self.animator updateItemUsingCurrentState:item];
  20. }
  21. return NO;
  22. }

步骤四:遵守委托协议,实现协议方法

首先在TRViewController的viewDidLoad方法中创建TRCollectionViewSpringCellLayout对象layout,并设置相关属性,代码如下所示:

 
  1. - (void)viewDidLoad
  2. {
  3. [super viewDidLoad];
  4. TRCollectionViewSpringCellLayout *layout = [[TRCollectionViewSpringCellLayout alloc]init];
  5. layout.itemSize = CGSizeMake(300, 40);
  6. layout.sectionInset = UIEdgeInsetsMake(0, 10, 0, 10);
  7. }

然后通过layout创建collectionView,并注册Cell,代码如下所示:

 
  1. static NSString *cellIdentifier = @"MyCell";
  2. - (void)viewDidLoad
  3. {
  4. [super viewDidLoad];
  5. TRCollectionViewSpringCellLayout *layout = [[TRCollectionViewSpringCellLayout alloc]init];
  6. layout.itemSize = CGSizeMake(300, 40);
  7. layout.sectionInset = UIEdgeInsetsMake(0, 10, 0, 10);
  8. UICollectionView *collectionView = [[UICollectionView alloc]initWithFrame:self.view.frame collectionViewLayout:layout];
  9. collectionView.showsVerticalScrollIndicator = NO;
  10. collectionView.showsHorizontalScrollIndicator = NO;
  11. collectionView.dataSource = self;
  12. [collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:cellIdentifier];
  13. [self.view addSubview:collectionView];
  14. }

最后实现集合视图的协议方法给集合视图加载数据,代码如下所示:

 
  1. - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
  2. {
  3. return 50;
  4. }
  5. - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
  6. {
  7. UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
  8. cell.backgroundColor = [UIColor randomColor];
  9. return cell;
  10. }

1.4 完整代码

本案例中,TRViewController.m文件中的完整代码如下所示:

 
  1. #import "TRViewController.h"
  2. #import "TRCollectionViewSpringCellLayout.h"
  3. #import "UIColor+RandomColor.h"
  4. @implementation TRViewController
  5. static NSString *cellIdentifier = @"MyCell";
  6. - (void)viewDidLoad
  7. {
  8. [super viewDidLoad];
  9. TRCollectionViewSpringCellLayout *layout = [[TRCollectionViewSpringCellLayout alloc]init];
  10. layout.itemSize = CGSizeMake(300, 40);
  11. layout.sectionInset = UIEdgeInsetsMake(0, 10, 0, 10);
  12. UICollectionView *collectionView = [[UICollectionView alloc]initWithFrame:self.view.frame collectionViewLayout:layout];
  13. collectionView.showsVerticalScrollIndicator = NO;
  14. collectionView.showsHorizontalScrollIndicator = NO;
  15. collectionView.dataSource = self;
  16. [collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:cellIdentifier];
  17. [self.view addSubview:collectionView];
  18. }
  19. - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
  20. {
  21. return 50;
  22. }
  23. - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
  24. {
  25. UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
  26. cell.backgroundColor = [UIColor randomColor];
  27. return cell;
  28. }
  29. @end

本案例中,TRCollectionViewSpringCellLayout.m文件中的完整代码如下所示:

 
  1. #import "TRCollectionViewSpringCellLayout.h"
  2. @interface TRCollectionViewSpringCellLayout ()
  3. @property (strong, nonatomic) UIDynamicAnimator *animator;
  4. @end
  5. @implementation TRCollectionViewSpringCellLayout
  6. //布局前的准备,布局开始前自动调用
  7. - (void)prepareLayout
  8. {
  9. //给每个一Cell创建UIAttachmentBehavior
  10. if(!self.animator){
  11. //通过集合视图布局创建animator对象
  12. self.animator = [[UIDynamicAnimator alloc]initWithCollectionViewLayout:self];
  13. CGSize contentSize = self.collectionViewContentSize;
  14. //获取所有的items
  15. NSArray *items = [super layoutAttributesForElementsInRect:CGRectMake(0, 0, contentSize.width, contentSize.height)];
  16. for (UICollectionViewLayoutAttributes *attributes in items) {
  17. UIAttachmentBehavior *spring = [[UIAttachmentBehavior alloc]initWithItem:attributes attachedToAnchor:attributes.center];
  18. spring.damping = 0.6;
  19. spring.frequency = 0.8;
  20. [self.animator addBehavior:spring];
  21. }
  22. }
  23. }
  24. //在集合视图滚动时会自动调用,返回所有cell的属性,并传递可见的矩形区域
  25. - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
  26. {
  27. //当collectionView需要layout信息时由animator提供
  28. return [self.animator itemsInRect:rect];
  29. }
  30. - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
  31. {
  32. return [self.animator layoutAttributesForCellAtIndexPath:indexPath];
  33. }
  34. //当bounds发生变化时,调用方法,为不同的Cell改变不同的锚点
  35. - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
  36. {
  37. UIScrollView *scrollView = self.collectionView;
  38. //获取滚动的距离
  39. CGFloat scrollDelta = newBounds.origin.y - scrollView.bounds.origin.y;
  40. //手指所在的位置
  41. CGPoint touchLocation = [scrollView.panGestureRecognizer locationInView:scrollView];
  42. //计算和改动每一个Cell的锚点
  43. for (UIAttachmentBehavior *spring in self.animator.behaviors) {
  44. UICollectionViewLayoutAttributes *item = [spring.items firstObject];
  45. CGPoint center = item.center;
  46. CGPoint anchorPoint = spring.anchorPoint;
  47. CGFloat distance = fabsf(touchLocation.y - anchorPoint.y);
  48. CGFloat scrollResistance = distance / 600;
  49. center.y += (scrollDelta>0)?MIN(scrollDelta, scrollDelta * scrollResistance):MAX(scrollDelta, scrollDelta * scrollResistance);
  50. item.center = center;
  51. //当item处于动画中时,如果对象主动修改了位置信息, 需要更新动画
  52. [self.animator updateItemUsingCurrentState:item];
  53. }
  54. return NO;
  55. }
  56. @end

本案例中,UIColor+RandomColor.h文件中的完整代码如下所示:

 
  1. #import <UIKit/UIKit.h>
  2. @interface UIColor (RandomColor)
  3. + (UIColor *)randomColor;
  4. @end

本案例中,UIColor+RandomColor.m文件中的完整代码如下所示:

 
  1. #import "UIColor+RandomColor.h"
  2. @implementation UIColor (RandomColor)
  3. + (UIColor *)randomColor
  4. {
  5. CGFloat red = arc4random() % 256 / 256.0;
  6. CGFloat green = arc4random() % 256 / 256.0;
  7. CGFloat blue = arc4random() % 256 / 256.0;
  8. return [UIColor colorWithRed:red green:green blue:blue alpha:1.0];
  9. }
  10. @end

2 给视图添加MotionEffect特效

2.1 问题

UIMotionEffect是iOS7中新增加一个类,它能帮助开发者为用户界面加上运动拟真效果,本案例使用UIMotionEffect给视图添加MotionEffect特效,如图-2所示:

图-2

2.2 方案

首先在Storyboard中搭建界面,在View中拖放一个ImageView控件作为backgroundView,在右边栏的检查器中设置好ImageView的显示图片。然后再拖放一个View控件覆盖在ImageView上面作为foregroundView,大小比ImageView略小,View控件里面是一个TextView控件,给TextView控件添加一些显示内容。

其次将ImageView控件和View关联成ViewController的属性backgroundView和foregroundView。

然后在viewDidLoad方法中给backgroundView和foregroundView添加MotionEffect效果。

最后需要在真机里面运行才能看到backgroundView和foregroundView根据设备的移动而产生偏移。

2.3 步骤

实现此案例需要按照如下步骤进行。

步骤一:搭建Storyboard界面

首先在Storyboard中搭建界面,在View中拖放一个和View同等大小的ImageView控件作为backgroundView,这里需要注意为了保证视图偏移的时候不会有空白,所以ImageView的大小要设置的比屏幕大,这里ImageView的frame设置为-100,-100,520,760。

然后在右边栏的检查器中设置好ImageView的显示图片。然后再拖放一个View控件覆盖在ImageView上面作为foregroundView,大小比ImageView略小,View控件里面是一个TextView控件,给TextView控件添加一些显示内容,Storyboard界面效果如图-3所示:

图-3

步骤二:创建添加MotionEffect效果

首先将ImageView控件和View关联成ViewController的属性backgroundView和foregroundView,代码如下所示:

 
  1. @interface ViewController ()
  2. @property (weak, nonatomic) IBOutlet UIImageView *backgroundView;
  3. @property (weak, nonatomic) IBOutlet UIView *foregroundView;
  4. @end

然后在viewDidLoad方法中给backgroundView和foregroundView添加MotionEffect效果,代码如下所示:

 
  1. - (void)viewDidLoad {
  2. [super viewDidLoad];
  3. self.foregroundView.layer.cornerRadius = 6.0f;
  4. self.foregroundView.layer.masksToBounds = YES;
  5. //给foregroundView添加MotionEffect
  6. UIInterpolatingMotionEffect *xAxis = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x" type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
  7. //设置x轴的最大和最小偏移值
  8. xAxis.minimumRelativeValue = @(-15.0);
  9. xAxis.maximumRelativeValue = @(15.0);
  10. UIInterpolatingMotionEffect *yAxis = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.y" type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
  11. yAxis.minimumRelativeValue = @(-15.0);
  12. yAxis.maximumRelativeValue = @(15.0);
  13. //创建UIMotionEffectGroup对象
  14. UIMotionEffectGroup *foregroundMotionEffect = [[UIMotionEffectGroup alloc] init];
  15. foregroundMotionEffect.motionEffects = @[xAxis, yAxis];
  16. //添加MotionEffect
  17. [self.foregroundView addMotionEffect:foregroundMotionEffect];
  18. //给backgroundView添加MotionEffect
  19. UIInterpolatingMotionEffect *xAxis2 = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x" type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
  20. //设置y轴的最大和最小偏移值
  21. xAxis2.minimumRelativeValue = @(25.0);
  22. xAxis2.maximumRelativeValue = @(-25.0);
  23. UIInterpolatingMotionEffect *yAxis2 = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.y" type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
  24. yAxis2.minimumRelativeValue = @(32.0);
  25. yAxis2.maximumRelativeValue = @(-32.0);
  26. UIMotionEffectGroup *backgroundMotionEffect = [[UIMotionEffectGroup alloc] init];
  27. backgroundMotionEffect.motionEffects = @[xAxis2, yAxis2];
  28. [self.backgroundView addMotionEffect:backgroundMotionEffect];
  29. }

步骤三:真机上运行程序

由于MotionEffect是根据设备的运动而产生的,所以需要在真机里面运行才能看到backgroundView和foregroundView根据设备的移动而产生偏移,真机上运行效果如图-4、图-5、图-6、图-7所示:

图-4

图-5

图-6

图-7

2.4 完整代码

本案例中,ViewController.m文件中的完整代码如下所示:

 
  1. #import "ViewController.h"
  2. @interface ViewController ()
  3. @property (weak, nonatomic) IBOutlet UIImageView *backgroundView;
  4. @property (weak, nonatomic) IBOutlet UIView *foregroundView;
  5. @end
  6. @implementation ViewController
  7. - (void)viewDidLoad {
  8. [super viewDidLoad];
  9. self.foregroundView.layer.cornerRadius = 6.0f;
  10. self.foregroundView.layer.masksToBounds = YES;
  11. //给foregroundView添加MotionEffect
  12. UIInterpolatingMotionEffect *xAxis = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x" type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
  13. //设置最大和最小偏移值
  14. xAxis.minimumRelativeValue = @(-15.0);
  15. xAxis.maximumRelativeValue = @(15.0);
  16. UIInterpolatingMotionEffect *yAxis = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.y" type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
  17. yAxis.minimumRelativeValue = @(-15.0);
  18. yAxis.maximumRelativeValue = @(15.0);
  19. UIMotionEffectGroup *foregroundMotionEffect = [[UIMotionEffectGroup alloc] init];
  20. foregroundMotionEffect.motionEffects = @[xAxis, yAxis];
  21. [self.foregroundView addMotionEffect:foregroundMotionEffect];
  22. //给backgroundView添加MotionEffect
  23. UIInterpolatingMotionEffect *xAxis2 = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x" type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
  24. xAxis2.minimumRelativeValue = @(25.0);
  25. xAxis2.maximumRelativeValue = @(-25.0);
  26. UIInterpolatingMotionEffect *yAxis2 = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.y" type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
  27. yAxis2.minimumRelativeValue = @(32.0);
  28. yAxis2.maximumRelativeValue = @(-32.0);
  29. UIMotionEffectGroup *backgroundMotionEffect = [[UIMotionEffectGroup alloc] init];
  30. backgroundMotionEffect.motionEffects = @[xAxis2, yAxis2];
  31. [self.backgroundView addMotionEffect:backgroundMotionEffect];
  32. }
  33. @end

3 给图片添加模糊效果

3.1 问题

IOS7在视觉方面有许多改变,其中非常吸引人的功能之一就是在整个系统中巧妙的使用了模糊效果,本案例使用UIImage+ImageBlur分类给图片添加各种模糊效果,如图-8所示:

图-8

3.2 方案

首先在Storyboard中搭建界面,场景中拖放一个ImageView控件和五个Button控件,在右边栏设置好ImageView的显示图片,然后分别将Button的tag设置为0、1、2、3、4,别分代表不同的图片模糊效果。

其次将ImageView关联成ViewController的属性imageView,将五个Button关联同一个方法changeEffect:。

然后导入UIImage+ImageBlur文件,该分类提供的几种图片模糊效果的方法。

最后实现changeEffect:方法,该方法根据用户的选择,通过image的图片模糊方法实现不同的图片的模糊效果。

3.3 步骤

实现此案例需要按照如下步骤进行。

步骤一:搭建Stroyboard界面

首先在Storyboard中搭建界面,场景中拖放一个ImageView控件和五个Button控件,在右边栏设置好ImageView的显示图片,然后分别将Button的tag设置为0、1、2、3、4,别分代表不同的图片模糊效果,搭建好的界面如图-9所示:

图-9

然后将ImageView关联成ViewController的属性imageView,将五个Button关联同一个方法changeEffect:,代码如下所示:

 
  1. @interface ViewController ()
  2. @property (weak, nonatomic) IBOutlet UIImageView *imageView;
  3. @end

步骤二:实现图片模糊效果

首先导入UIImage+ImageBlur文件,该分类提供的几种图片模糊效果的方法。

然后实现changeEffect:方法,该方法根据用户的选择,通过image的图片模糊方法实现不同的图片的模糊效果,代码如下所示:

 
  1. - (IBAction)changeEffect:(UIButton *)sender {
  2. UIImage *effectImage;
  3. switch (sender.tag) {
  4. case 0:
  5. effectImage = [self.imageView.image applyLightEffect];
  6. break;
  7. case 1:
  8. effectImage = [self.imageView.image applyExtraLightEffect];
  9. break;
  10. case 2:
  11. effectImage = [self.imageView.image applyDarkEffect];
  12. break;
  13. case 3:
  14. effectImage = [self.imageView.image applyTintEffectWithColor:[UIColor lightGrayColor]];
  15. break;
  16. case 4:
  17. effectImage = [UIImage imageNamed:@"xiaoqingxin07.jpg"];
  18. break;
  19. }
  20. self.imageView.image = effectImage;
  21. }

运行程序可以看到LightEffect、ExtraLightEffect、DarkEffect、TintEffectWithColor等图片模糊效果分别如图-10、图-11、图-12及图-13所示:

图-10

图-11

图-12

图-13

3.4 完整代码

本案例中,ViewController.m文件中的完整代码如下所示:

 
  1. #import "ViewController.h"
  2. #import "UIImage+ImageEffects.h"
  3. @interface ViewController ()
  4. @property (weak, nonatomic) IBOutlet UIImageView *imageView;
  5. @end
  6. @implementation ViewController
  7. - (IBAction)changeEffect:(UIButton *)sender {
  8. UIImage *effectImage;
  9. switch (sender.tag) {
  10. case 0:
  11. effectImage = [self.imageView.image applyLightEffect];
  12. break;
  13. case 1:
  14. effectImage = [self.imageView.image applyExtraLightEffect];
  15. break;
  16. case 2:
  17. effectImage = [self.imageView.image applyDarkEffect];
  18. break;
  19. case 3:
  20. effectImage = [self.imageView.image applyTintEffectWithColor:[UIColor lightGrayColor]];
  21. break;
  22. case 4:
  23. effectImage = [UIImage imageNamed:@"xiaoqingxin07.jpg"];
  24. break;
  25. }
  26. self.imageView.image = effectImage;
  27. }
  28. @end

4 演示属性字符串的用法

4.1 问题

NSAtrributeString属性字符串是基于TextKit来构建的字符串对象,将字符串和样式信息组合在一起。本案例演示属性字符串的用法,如图-14所示:

图-14

4.2 方案

首先在viewDidLoad方法中创建一个NSDictionary类型的对象attributes,以键值对的方式管理字符串的样式信息。

其次创建一个NSAttributedString类型的字符串attrString,使用initWithString:attributes:方法进行初始化,string参数是字符串的内容,attributes参数就是上一步创建的attributes对象,即字符串的样式信息。

然后再创建一个NSMutableAttributedString类型的字符串mAttrString,与NSAttributedString类型不同的是NSMutableAttributedString类型是可变的属性字符串。

可以使用addAttribute:value:range:方法,或者addAttributes:range:方法给mAttrString添加样式,两个方法的区别就是前者只能添加一个键值对表示的样式,后者可以添加多个键值对表示的样式。

最后将mAttrString设置为self.label.attributedText属性,即可在界面看见带有属性样式的字符串。

4.3 步骤

实现此案例需要按照如下步骤进行。

步骤一:搭建Storyboard界面

首先Storyboard的场景中拖放一个Label控件,并将Label控件关联成TRViewController的属性label,代码如下所示:

 
  1. @interface TRViewController ()
  2. @property (weak, nonatomic) IBOutlet UILabel *label;
  3. @end

步骤二:创建属性字符串

首先在viewDidLoad方法中创建一个NSDictionary类型的对象attributes,以键值对的方式管理字符串的样式信息,NSForegroundColorAttributeName是key表示前景色即字符串的颜色,对应的value是一个UIColor类型的对象。NSFontAttributeName也是key表示字体名称,对应的value是一个UIFont类型的对象,代码如下所示:

 
  1. - (void)viewDidLoad
  2. {
  3. [super viewDidLoad];
  4. NSDictionary *attributes = @{NSForegroundColorAttributeName : [UIColor redColor], NSFontAttributeName : [UIFont systemFontOfSize:26]};
  5. }

其次创建一个NSAttributedString类型的字符串attrString,使用initWithString:attributes:方法进行初始化,string参数是字符串的内容,attributes参数就是上一步创建的attributes对象,即字符串的样式信息,代码如下所示:

 
  1. - (void)viewDidLoad
  2. {
  3. [super viewDidLoad];
  4. NSDictionary *attributes = @{NSForegroundColorAttributeName : [UIColor redColor], NSFontAttributeName : [UIFont systemFontOfSize:26]};
  5. NSAttributedString *attrString = [[NSAttributedString alloc]initWithString:@"Hello World." attributes:attributes];
  6. }

然后再创建一个NSMutableAttributedString类型的字符串mAttrString,与NSAttributedString类型不同的是NSMutableAttributedString类型是可变的属性字符串,代码如下所示:

 
  1. - (void)viewDidLoad
  2. {
  3. [super viewDidLoad];
  4. NSDictionary *attributes = @{NSForegroundColorAttributeName : [UIColor redColor], NSFontAttributeName : [UIFont systemFontOfSize:26]};
  5. NSAttributedString *attrString = [[NSAttributedString alloc]initWithString:@"Hello World." attributes:attributes];
  6. NSMutableAttributedString *mAttrString = [attrString mutableCopy];
  7. }

再使用addAttribute:value:range:方法,或者addAttributes:range:方法给mAttrString添加样式,两个方法的区别就是前者只能添加一个键值对表示的样式,后者可以添加多个键值对表示的样式,代码如下所示:

 
  1. - (void)viewDidLoad
  2. {
  3. [super viewDidLoad];
  4. NSDictionary *attributes = @{NSForegroundColorAttributeName : [UIColor redColor], NSFontAttributeName : [UIFont systemFontOfSize:26]};
  5. NSAttributedString *attrString = [[NSAttributedString alloc]initWithString:@"Hello World." attributes:attributes];
  6. NSMutableAttributedString *mAttrString = [attrString mutableCopy];
  7. [mAttrString addAttribute:NSFontAttributeName value:[UIFont italicSystemFontOfSize:35] range:NSMakeRange(3, 2)];
  8. [mAttrString addAttributes:@{NSBackgroundColorAttributeName : [UIColor lightGrayColor], NSTextEffectAttributeName : NSTextEffectLetterpressStyle} range:NSMakeRange(6, 3)];
  9. }

最后将mAttrString设置为self.label.attributedText属性,即可在界面看见带有属性样式的字符串,代码如下所示:

 
  1. - (void)viewDidLoad
  2. {
  3. [super viewDidLoad];
  4. NSDictionary *attributes = @{NSForegroundColorAttributeName : [UIColor redColor], NSFontAttributeName : [UIFont systemFontOfSize:26]};
  5. NSAttributedString *attrString = [[NSAttributedString alloc]initWithString:@"Hello World." attributes:attributes];
  6. NSMutableAttributedString *mAttrString = [attrString mutableCopy];
  7. [mAttrString addAttribute:NSFontAttributeName value:[UIFont italicSystemFontOfSize:35] range:NSMakeRange(3, 2)];
  8. [mAttrString addAttributes:@{NSBackgroundColorAttributeName : [UIColor lightGrayColor], NSTextEffectAttributeName : NSTextEffectLetterpressStyle} range:NSMakeRange(6, 3)];
  9. self.label.attributedText = mAttrString;
  10. }

4.4 完整代码

本案例中,TRViewController.m文件中的完整代码如下所示:

 
  1. #import "TRViewController.h"
  2. @interface TRViewController ()
  3. @property (weak, nonatomic) IBOutlet UILabel *label;
  4. @end
  5. @implementation TRViewController
  6. - (void)viewDidLoad
  7. {
  8. [super viewDidLoad];
  9. NSDictionary *attributes = @{NSForegroundColorAttributeName : [UIColor redColor], NSFontAttributeName : [UIFont systemFontOfSize:26]};
  10. NSAttributedString *attrString = [[NSAttributedString alloc]initWithString:@"Hello World." attributes:attributes];
  11. NSMutableAttributedString *mAttrString = [attrString mutableCopy];
  12. [mAttrString addAttribute:NSFontAttributeName value:[UIFont italicSystemFontOfSize:35] range:NSMakeRange(3, 2)];
  13. [mAttrString addAttributes:@{NSBackgroundColorAttributeName : [UIColor lightGrayColor], NSTextEffectAttributeName : NSTextEffectLetterpressStyle} range:NSMakeRange(6, 3)];
  14. self.label.attributedText = mAttrString;
  15. }
  16. @end

Dynamic支持CollectionView布局 、 MotionEffects特效 、 BlurImage效果 、 TextKit的更多相关文章

  1. HMS Core音频编辑服务支持7种音频特效,助力一站式音频处理

    多媒体时代,音频作为内容传播中的重要形式,因其不受空间限制.认知负担小.声音元素多样化等特点,广泛应用于短视频制作.儿童在线教育.有声阅读.游戏等领域产品,在各种形式的音频呈现过程中,合理添加音效能够 ...

  2. jquery特效 幻灯片效果

    jquery特效 幻灯片效果,效果图如下: <!DOCTYPE html> <html> <head> <meta http-equiv="Cont ...

  3. Javscript轮播 支持平滑和渐隐两种效果(可以只有两张图)

    原文:Javscript轮播 支持平滑和渐隐两种效果(可以只有两张图) 先上两种轮播效果:渐隐和移动   效果一:渐隐 1 2 3 4 效果二:移动 1 2 3 4 接下来,我们来大致说下整个轮播的思 ...

  4. Javascript轮播 支持平滑和渐隐两种效果

    Javascript轮播 支持平滑和渐隐两种效果 先上两种轮播效果:渐隐和移动   效果一:渐隐 1 2 3 4 效果二:移动 1 2 3 4 接下来,我们来大致说下整个轮播的思路: 一.先来看简单的 ...

  5. 编写Java程序,现要求使用 dom4j 解析 city.xml 文档,实现省份及对应城市的联动特效,效果如图所示

    查看本章节 查看作业目录 需求说明: 现要求使用 dom4j 解析 city.xml 文档,实现省份及对应城市的联动特效,效果如图所示 实现思路: 创建解析 XML 文档类 ParseXML 和窗体类 ...

  6. 【CSS进阶】伪元素的妙用2 - 多列均匀布局及title属性效果

    最近无论是工作还是自我学习提升都很忙,面对长篇大论的博文总是心有余而力不足,但又不断的接触学习到零碎的但是很有意义的知识点,很想分享给大家,所以本篇可能会很短. 本篇接我另一篇讲述 CSS 伪元素的文 ...

  7. collectionView布局原理及瀑布流布局方式

    一直以来都想研究瀑布流的具体实现方法(起因是因为一则男女程序员应聘的笑话,做程序的朋友应该都知道).最近学习到了瀑布流的实现方法,瀑布流的实现方式有多种,这里应用collectionView来重写其U ...

  8. Swift - 使用CollectionView实现图片Gallery画廊效果(左右滑动浏览图片)

    1,效果图 (1)图片从左至右横向排列(只有一行),通过手指拖动可以前后浏览图片. (2)视图滚动时,每张图片根据其与屏幕中心距离的不同,显示尺寸也会相应地变化.越靠近屏幕中心尺寸就越大,远离屏幕中心 ...

  9. 微软借力.NET开源跨平台支持,布局物联网平台开发

    今天科技类最大的新闻,莫过于微软宣布.NET开发框架开源计划..NET 开源,集成 Clang 和 LLVM 并且自带 Android 模拟器,这意味着 Visual Studio 这个当下最好没有之 ...

随机推荐

  1. Entity Framework 复杂类型

      为了说明什么是复杂属性,先举一个例子. public class CompanyAddress { public int ID { get; set; } public string Compan ...

  2. hadoop工作流引擎之azkaban [转]

    介绍 Azkaban是twitter出的一个任务调度系统,操作比Oozie要简单很多而且非常直观,提供的功能比较简单.Azkaban以Flow为执行单元进行定时调度,Flow就是预定义好的由一个或多个 ...

  3. jquery 添加方法 : $.fn.方法名 = function(参数a,b,c){

    $.fn.image_checked = function(self,status,img_body,csrf_token){             $(this).live('click', fu ...

  4. Windows XP PRO SP3 - Full ROP calc shellcode

    /*     Shellcode: Windows XP PRO SP3 - Full ROP calc shellcode     Author: b33f (http://www.fuzzysec ...

  5. php file_get_contents curl发送cookie,使用代理

    $auth = base64_encode('LOGIN:PASSWORD');//LOGIN:PASSWORD 这里是你的账户名及密码 $aContext = array( 'http' => ...

  6. 在oracle中使用Trigger

    1.初始目标 在对表h1插入一条数据时,同时插入一条重复的数据(只有主键不同) 2.在PL/SQL里New一个Trigger或者手动敲入代码 先说明一下,表h1包括4列ID.C1.C2.C3 crea ...

  7. Deep Learning 初识

    实际生活中,人们为了解决一个问题,如对象的分类(对象可是是文档.图像等),首先必须做的事情是如何来表达一个对象,即必须抽取一些特征来表示一个对象,如文本的处理中,常常用词**来表示一个文档,或把文档表 ...

  8. 哪些字符需要urlencode编码?具体怎么处理?

    哪些字符需要urlencode编码?具体怎么处理? JS用escape()/encodeURI()/encodeURIComponent()方法编码,用unescape()/decodeURI()/e ...

  9. php可变变量

    例子: <?php $a = "b"; $$a = "c"; echo $$a; echo "<br>"; echo $b ...

  10. Gmail新版截图曝光 你还能认得出来吗?

    Gmail即将迎来巨大的改变.据外媒消息,目前Google正在测试新的网页版Gmail.要知道从Gmail推出以来还从未进行过如此大的改动. 新版Gmail中,界面相比之前,采用了更加扁平话的设计,整 ...