视错觉:从一个看似简单的自定义控件说起

 为什么要写今天这篇博客那就说来话长了,那是在一个大雪纷飞的冬天……然后……。好了,不扯淡了,直接进入今天的主题吧,这篇博客是关于iOS自定义组件的东西。一些UI效果看起来似乎是这个样子,其实本质不是这个样子。在做一些UI效果时我们可以利用视错觉的一些东西,让用户看到的是一个东西,其实你实现的又是一个东西。原则是想方设法骗过用户的眼睛。视错觉如果和UI实现结合起来,有时会产生意想不到的效果。

  一.视错觉的概述

    引用--“视错觉就是当人观察物体时,基于经验主义或不当的参照形成的错误的判断和感知。视错:是指 观察者在客观因素干扰下或者自身的心理因素支配下,对图形产生的与客观事实不相符的错误的感觉。”

    看上面这个解释似乎有点复杂,其实说白了就是欺骗你自己的眼睛。眼见不一定为实。视错觉的常用例子:矮中见高、虚中见实、冷调降温、粗中见细、曲中见直等等常用的手法。说这么多,接下来我想用一组图来直观的感受一下视错觉。(图片来源与网络)

    1.这里不是起点,那里也不是终点。

    2.平衡?别想了。

    3.一个非常经典的幻觉。

    上面是在网上找的视错觉的图片,像上面这些视错觉的经典案例还有很多呢,请大家自行百度吧。上面算是今天博客的引子吧,接下来就和开发有关了。

 

  二、一个利用视错觉的自定义组件

    当第一次看到这个组件效果时,感觉没有什么特别之处,就是一个普通在普通不过的组件。可是再仔细看就感觉不一样了,一些细节处理的非常好。看到组件效果时,因为没有源码,所以当时也不知道如何实现的。就想呗,然后就想到了用“视错觉”这个高大上的东西来实现。当然这个实现方案是我自己想出来的,我不知道原作者是如何实现的,下面给出了我自己的实现方案。 说这么多,先来看一下运行效果吧。

    1. 该组件的运行效果如下,其实就是一个自定义的SegmentControl。看到该组件的时候,我的第一印象是:“这个组件应该挺好做的”。当时感觉就是几个Button, 然后红色的是一个UIView, 点击那个Button时,就把UIView通过动画的形式移动到当前点击的Button。顶多就是封装一下,成为一个自定义组件,然后给别人使用。

    2. 在仔细看效果,感觉自己还是太年轻,太单纯了。这个组件远远不是我想的那样,上面组件的实现的重点与难点不在于如何去运动,如何去封装它。而在于下面这个截图中的东西。如果把动画放慢,你会发现一个细节,这个细节处理的非常的巧妙,也是这个组件的亮点与难点所在。下方是切换时放慢的一个效果。看到这个细节时,瞬间颠覆了我之前单纯的想法。这个组件远远没有我想的这么简单。

    在切换时,有一个细节,就是在红色区域中的文字(或文字的一部分)随着红色区域的移动,文字的颜色也会随之部分改变。当红色区域移动过后,字体颜色又变为原来的了。看到这个效果,对这个组件的崇拜感就油然而生了。瞬间也蒙圈了,一时没有解决思路。大脑中充满了无数的问号。这究竟用了什么黑科技!?实现了这么NX的效果。晚上做地铁回家的时候也一直在想其解决方案。果然在地铁上灵光一现,应该就是用它:“视错觉”。于是乎就回家晚饭都没吃,就拿出笔记本开始按着自己的思路去实现。功夫不负有心人呢,所以才有了今天的博客。当然实现上述效果是我自己的思路,如果还有其他更好的实现方式欢迎交流。

 

  三、实现原理

    1.原理介绍

    实现上述效果时,如果按着我看到的就是看到的来实现的话,估计会无从下手的。一个原则:“眼见为虚”,就OK了。今天这篇博客,我不想往上粘贴过多的代码,还是把我的思路给大家分享一下就好。其实编程这东西,有时候思路比代码更为重要。下方我想用在Reveal工具上的分析层次来给大家聊一下实现原理。

    通过Reveal上面的UI层次我们很容易看出,这个组件远比我们想象的要复杂的多。我的实现方式如下:

      (1) 先在View上加上一层的Label, 这些Label用来显示常规的字体颜色(未选中时的颜色)(黑色的字)

      (2) 在之前的Label上添加一层View , 动画元素,高亮显示的字体,点击的按钮都在这个View上

      (3) 在这个View上添加一层高亮的Label(白色的字), Label的字体,大小,位置等要和底层的Label一致(除了颜色除外)

      (4) 上层的View的大小要和一个Label的大小一致,并且设置超出View的子视图不显示。

      (5) 移动View(红色部分)时,也要移动View上白色的字。要保持移动的过程中,白色Label和黑色label完全重合。

    这样View移动到那个label上时,就会把后边的黑色Label给挡上,显示的是上面白色的Label.原理大概就是这个原理,原理一旦知道怎么回事了,至于实现起来就简单许多了。 


   2.该自定组件可配置项如下:

//
//  ZLCustomeSegmentControlView.h
//  CustomeSegmentControl
//
//  Created by ZeluLi on 15/11/19.
//  Copyright  2015年 zeluli. All rights reserved.
//

#import <UIKit/UIKit.h>

typedef void(^ButtonOnClickBlock)(NSInteger tag, NSString * title);

@interface ZLCustomeSegmentControlView : UIView

@property (nonatomic, strong) NSArray *titles;                      //标题数组
@property (nonatomic, strong) UIColor *titlesCustomeColor;          //标题的常规颜色
@property (nonatomic, strong) UIColor *titlesHeightLightColor;      //标题高亮颜色
@property (nonatomic, strong) UIColor *backgroundHeightLightColor;  //高亮时的颜色
@property (nonatomic, strong) UIFont *titlesFont;                   //标题的字号
@property (nonatomic, assign) CGFloat duration;                     //运动时间

/**
 *  点击按钮的回调
 *
 *  @param block 点击按钮的Block
 */
-(void) setButtonOnClickBlock: (ButtonOnClickBlock) block;

@end

 

   3.该自定义组件的调用方式

ZLCustomeSegmentControlView *v = [[ZLCustomeSegmentControlView alloc] initWithFrame:CGRectMake(30, 100, SCREEN_WIDTH - 60, 50)];

    v.titles = @[@"Hello", @"Apple", @"Swift", @"Objc"];
    v.duration = 0.7f;

    [v setButtonOnClickBlock:^(NSInteger tag, NSString *title) {
        NSLog(@"index = %ld, title = %@", (long)tag, title);
    }];

    [self.view addSubview:v];

由于某些原因呢,今天博客中就不一一往上粘贴代码了。有好的思路欢迎交流~

时间: 2024-08-03 00:24:56

视错觉:从一个看似简单的自定义控件说起的相关文章

一个看似简单实则颇有些难度的go语言问题,关于密码输入

问题描述 一个看似简单实则颇有些难度的go语言问题,关于密码输入 RT. 具体要求:输入一串字符(中间可能有各种空格啊符号啊之类)作为密码,以回车键结束 由于是密码,所以输入时屏幕不能明文显示,当每输入一个字符则显示为一个*,最后密码由一个string型变量获取 好像用go语言不是那么好实现,尤其是考虑到退格键以及方向键改变输入顺序的问题(比如输入的时候用方向键将光标前移后插入内容),还有delete键带来的删除效果-- 各位大神有什么好的解决方案?期待最简洁的代码--

一个看似简单又复杂的sql题

问题描述 现在有三张表1.教师表(teacher)结构为teacher_id,teacher_name2.学生表(student)结构为student_id,student_name3.教师学生关联表(teacher_students)结构为teacher_id,students前两张就不用说了,第三张的students数据结构如下student_id:is_later;student_id:is_later的结构student_id表示的是学生id,is_later表示是否迟到,现在考虑要展示

SEO看似简单但更应该拒绝浮躁的心理

SEO一提起嘛,不外乎就是原创加外链,我相信这个已经是被提烂了的说法了,所以好多人一来就觉得SEO太简单了,不就是写写文章嘛,发发外链嘛,这个谁不会啊,也就是好多人天天没命的写原创,网站为什么还是不收录;好多人疯狂的发外链,为什么排名还是没有上升,天天在QQ群里边这样的人太多了,简直是数不甚数,所以SEO也才被人为民工职业,也是好多人选择了退出的原因,其实真的是这样吗,或许好多人在说这句话之前都忽略了一个前提,而且是一个很重要的前提:那就是在做这些原创和外链之前就是网站已经完全搭建好了,而且也是

最简单的自定义控件

ASP.NET提供自定义控件的机制,本文记叙生成一个简单自定义控件的方法. 一般地,Web页面处理发生错误时,可以在页面上显示错误信息,也可以通过javascript的alert提示信息.在ASP.NET中实现alert的一种方法是定义自定义控件. 小鸡射手的PromptControl实现如下,实在算是最简单的自定义控件啦,:-) [DefaultProperty("Message"), ToolboxData("<{0}:PromptControl runat=ser

移动互联网有一个很简单的矛盾难以调和

摘要: 移动互联网有一个很简单的矛盾难以调和,当下移动设备尚无法比拟PC之时,人们对移动设备的使用却远超PC,而在这样的大环境下,使用者希望移动应用既能够具有如PC软件一样强大的 移动互联网有一个很简单的矛盾难以调和,当下移动设备尚无法比拟PC之时,人们对移动设备的使用却远超PC,而在这样的大环境下,使用者希望移动应用既能够具有如PC软件一样强大的使用广度,又尽可能简单到能够让设备可以承受.这形成了一个"加减法",而对于移动搜索来说,这个"加减法"尤其难做. 移动搜

Ultradev实例教程:5 做一个相对简单的网站后台(1)

后台|教程 第五章:做一个相对简单的网站后台(1) 在这一节的内容中,我们将综合利用到我们前面学到的显示.插入.编辑.删除等功能来实现一个相对简单的新闻发布系统. 先介绍一下这个新闻发布系统的构成: 前台部分:首页上显示最新更新的5条新闻,点击新闻的标题察看详细信息(包括新闻的内容,相关连接),另外还有一个More的连接,指向一页可以每页显示10条记录. 后台部分:通过一个密码验证页面登录进功能选择页面.功能选择页面提供增加.删除.修改管理用户和增加.删除.修改新闻的跳转. 按照我们前面课程的介

Ultradev实例教程:5 做一个相对简单的网站后台(3

后台|教程 第五章:做一个相对简单的网站后台(3) 删除的页面怎么做呢?咦?忘了我们上面讲的吗?用command对象,很简单就完成了: 测试一下先.删掉我们刚刚编辑过的那条数据,嗯,也很正常----不正常才怪呢 :) 一般我们添加.删除.编辑完了数据之后都会有一些提示,或者要跳转到另外一个页面去.比如我们删除操作(del_article.asp)完成后要跳回数据显示页面,怎么办?用html里面的refresh标记.呵呵,是不是突然拍拍脑袋有恍然大悟的感觉.老是在asp中转来转去,html的东西都

Ultradev实例教程:5 做一个相对简单的网站后台(2)

后台|教程 首先创建首页,就是现实最新更新的5条新闻纪录.利用我们学到的Ultradev显示纪录的功能,很容易你就能创建好如下图的页面: 怎么显示最新更新的5条记录呢?让我们来看看创建记录集的对话框: 如果我们按照一般创建记录集的方法,在上图中的SQL栏中显示的内容就会是: SELECT ID,title,insert_time (我们只需要显示新闻的标题和记录时间,而新闻内容不需要现实,所以不用选择content这个字段) FROM article 我们将她修改成上面的样子.top 5表示我只

以一个最简单的例子把OO的JavaScript说明白

javascript  OO的JavaScript并不高深,麻烦就麻烦在google出来的国人介绍文章经常罗罗嗦嗦,而且之间的说法还各有不同,摆在一起就让人看了头大.这里重拾简单主义,以一个最简单的例子把OO Javascript说明白. 1.一个颇为精简的例子 //定义Circle类function Circle(radius) {    this.r = radius;}Circle.PI = 3.14159;Circle.prototype.area = function(  ) {ret