CALayer詳細(xì)講解

CALayer1-簡介

本文目錄

一秒紧、什么是CALayer

二、CALayer的簡單使用

回到頂部

一、什么是CALayer

* 在iOS系統(tǒng)中够滑,你能看得見摸得著的東西基本上都是UIView蛤高,比如一個按鈕蚣旱、一個文本標(biāo)簽碑幅、一個文本輸入框、一個圖標(biāo)等等塞绿,這些都是UIView沟涨。

* 其實(shí)UIView之所以能顯示在屏幕上,完全是因?yàn)樗鼉?nèi)部的一個層异吻。

* 在創(chuàng)建UIView對象時裹赴,UIView內(nèi)部會自動創(chuàng)建一個層(即CALayer對象),通過UIView的layer屬性可以訪問這個層诀浪。當(dāng)UIView需要顯示到屏幕上時棋返,會調(diào)用drawRect:方法進(jìn)行繪圖,并且會將所有內(nèi)容繪制在自己的層上雷猪,繪圖完畢后睛竣,系統(tǒng)會將層拷貝到屏幕上,于是就完成了UIView的顯示求摇。

* 換句話說射沟,UIView本身不具備顯示的功能,是它內(nèi)部的層才有顯示功能与境。

回到頂部

二验夯、CALayer的簡單使用

上面已經(jīng)說過了,UIView之所以能夠顯示摔刁,完全是因?yàn)閮?nèi)部的CALayer對象挥转。因此,通過操作這個CALayer對象簸搞,可以很方便地調(diào)整UIView的一些界面屬性扁位,比如:陰影、圓角大小趁俊、邊框?qū)挾群皖伾取?/p>

1.CALayer是被定義在QuartzCore框架中的域仇,因此要想使用CALayer,先導(dǎo)入QuartzCore框架

1> 點(diǎn)擊項(xiàng)目名稱寺擂,然后點(diǎn)擊右邊TARGETS下面的target

2> 點(diǎn)擊Build Pases后暇务,展開Link Binary....,添加 + 號

3> 在搜索框中輸入"Quartz"怔软,選中QuartzCore.framework垦细,最后add添加

4> 添加完畢后,這個框架就會出現(xiàn)在項(xiàng)目文件夾中

如果你覺得位置不好看挡逼,還可以將它拖到Frameworks文件夾下括改,跟其他框架放一起

2.在項(xiàng)目代碼中導(dǎo)入QuartzCore框架的主頭文件

#import

3.通過CALayer修改UIImageView的界面屬性

你也可以使用UIButton或者UILabel,這里就以UIImageView為例子

1> 先創(chuàng)建一個UIImageView家坎,添加到控制器的view中

1UIImage *image = [UIImage imageNamed:@"lufy.png"];2UIImageView *imageView =[[[UIImageView alloc] initWithImage:image] autorelease];3imageView.center = CGPointMake(100,100);4[self.view addSubview:imageView];

2> 設(shè)置陰影

1imageView.layer.shadowColor=[UIColor grayColor].CGColor;2imageView.layer.shadowOffset= CGSizeMake(10,10);3imageView.layer.shadowOpacity=0.5;

* 第1行設(shè)置陰影的顏色為灰色嘱能,注意吝梅,這里使用的是UIColor的CGColor屬性,是一種CGColorRef類型的數(shù)據(jù)

* 第2行設(shè)置陰影的偏移大小惹骂,可以看出陰影往原圖的右下角偏移

* 第3行設(shè)置陰影的不透明度為0.5苏携,表示半透明。如果為1对粪,代表完全不透明右冻。

3>設(shè)置圓角大小

通過layer屬性可以訪問視圖內(nèi)部的CALayer對象

1imageView.layer.cornerRadius=10;2imageView.layer.masksToBounds= YES;

* 第1行設(shè)置圓角半徑為10

* 第2行的maskToBounds=YES:可以看做是強(qiáng)制內(nèi)部的所有子層支持圓角效果,少了這個設(shè)置著拭,UIImageView是不會有圓角效果的

* 注意纱扭,如果設(shè)置了maskToBounds=YES,那將不會有陰影效果

4> 設(shè)置邊框?qū)挾群皖伾?/p>

1imageView.layer.borderWidth=5;2imageView.layer.borderColor= [UIColor redColor].CGColor;

* 第1行設(shè)置邊框?qū)挾葹?

* 第2行設(shè)置邊框顏色為紅色

5> 設(shè)置旋轉(zhuǎn)

imageView.layer.transform=CATransform3DMakeRotation(M_PI_4,0,0,1);

* 利用transform屬性可以設(shè)置旋轉(zhuǎn)茫死、縮放等效果

* M_PI_4表示四分之π跪但,順時針旋轉(zhuǎn)45°

* 后面的(0, 0, 1)表示Z軸這個向量,修改這個向量可以做一些三維旋轉(zhuǎn)效果峦萎,你可以隨便改個值試一下,比如(1, 1, 1)

* 總體的意思是layer會繞著Z軸順時針旋轉(zhuǎn)45°忆首,也就是在x爱榔、y平面進(jìn)行旋轉(zhuǎn)




CALayer2-創(chuàng)建新的層

本文目錄

一、添加一個簡單的圖層

二糙及、添加一個顯示圖片的圖層

三详幽、為什么CALayer中使用CGColorRef和CGImageRef這2種數(shù)據(jù)類型,而不用UIColor和UIImage浸锨?

四唇聘、UIView和CALayer的選擇

五、UIView和CALayer的其他關(guān)系

*上一講已經(jīng)說過柱搜,UIView內(nèi)部默認(rèn)有個CALayer對象(層)迟郎,通過layer屬性可以訪問這個層。要注意的是聪蘸,這個默認(rèn)的層不允許重新創(chuàng)建宪肖,但可以往層里面添加子層

*UIView可以通過addSubview:方法添加子視圖,類似地健爬,CALayer可以通過addSublayer:方法添加子層

接下來演示一下如何添加子層:

回到頂部

一控乾、添加一個簡單的圖層

1CALayer *myLayer =[CALayerlayer];2//設(shè)置層的寬度和高度(100x100)3myLayer.bounds= CGRectMake(0,0,100,100);4//設(shè)置層的位置5myLayer.position= CGPointMake(100,100);6//設(shè)置層的背景顏色:紅色7myLayer.backgroundColor=[UIColor redColor].CGColor;8//設(shè)置層的圓角半徑為109myLayer.cornerRadius=10;1011//添加myLayer到控制器的view的layer中12[self.view.layeraddSublayer:myLayer];

* 第1行創(chuàng)建了一個自動釋放的CALayer對象,你也可以使用經(jīng)典的alloc和init方法來創(chuàng)建

* 第12行將創(chuàng)建好的層添加到控制器的view的層中

回到頂部

二娜遵、添加一個顯示圖片的圖層

1CALayer *myLayer =[CALayerlayer];2//設(shè)置層的寬度和高度(100x100)3myLayer.bounds= CGRectMake(0,0,100,100);4//設(shè)置層的位置5myLayer.position= CGPointMake(100,100);6//設(shè)置需要顯示的圖片7myLayer.contents= (id)[UIImage imageNamed:@"lufy.png"].CGImage;8//設(shè)置層的圓角半徑為109myLayer.cornerRadius=10;10//如果設(shè)置了圖片蜕衡,需要設(shè)置這個屬性為YES才有圓角效果11myLayer.masksToBounds=YES;1213//添加myLayer到控制器的view的layer中14[self.view.layeraddSublayer:myLayer];

* 在第7行設(shè)置需要顯示的圖片,注意设拟,這里用的是UIImage的CGImage屬性慨仿,是一種CGImageRef類型的數(shù)據(jù)

回到頂部

三鸽扁、為什么CALayer中使用CGColorRef和CGImageRef這2種數(shù)據(jù)類型,而不用UIColor和UIImage镶骗?

* 首先要知道:CALayer是定義在QuartzCore框架中的桶现;CGImageRef、CGColorRef兩種數(shù)據(jù)類型是定義在CoreGraphics框架中的鼎姊;UIColor骡和、UIImage是定義在UIKit框架中的

* 其次,QuartzCore框架和CoreGraphics框架是可以跨平臺使用的相寇,在iOS和Mac OS X上都能使用慰于,但是UIKit只能在iOS中使用

* 因此,為了保證可移植性唤衫,QuartzCore不能使用UIImage婆赠、UIColor,只能使用CGImageRef佳励、CGColorRef

* 不過很多情況下休里,可以通過UIKit對象的特定方法,得到CoreGraphics對象赃承,比如UIImage的CGImage方法可以返回一個CGImageRef

回到頂部

四妙黍、UIView和CALayer的選擇

細(xì)心的朋友不難發(fā)現(xiàn),其實(shí)前面的2個效果不僅可以通過添加層來實(shí)現(xiàn)瞧剖,還可以通過添加UIView來實(shí)現(xiàn)拭嫁。比如,第1個紅色的層可以用一個UIView來實(shí)現(xiàn)抓于,第2個顯示圖片的層可以用一個UIImageView來實(shí)現(xiàn)做粤。既然CALayer和UIView都能實(shí)現(xiàn)相同的顯示效果,那究竟該選擇誰好呢捉撮?

* 其實(shí)怕品,對比CALayer,UIView多了一個事件處理的功能呕缭。也就是說堵泽,CALayer不能處理用戶的觸摸事件,而UIView可以

* 所以恢总,如果顯示出來的東西需要跟用戶進(jìn)行交互的話迎罗,用UIView;如果不需要跟用戶進(jìn)行交互片仿,用UIView或者CALayer都可以

* 當(dāng)然纹安,CALayer的性能會高一些,因?yàn)樗倭耸录幚淼墓δ埽虞p量級

回到頂部

五厢岂、UIView和CALayer的其他關(guān)系

*UIView可以通過subviews屬性訪問所有的子視圖光督,類似地,CALayer也可以通過sublayers屬性訪問所有的子層

*UIView可以通過superview屬性訪問父視圖塔粒,類似地结借,CALayer也可以通過superlayer屬性訪問父層

* 下面再看一張UIView和CALayer的關(guān)系圖:

如果兩個UIView是父子關(guān)系,那么它們內(nèi)部的CALayer也是父子關(guān)系卒茬。



CALayer3-層的屬性

本文目錄

一船老、隱式動畫屬性

二、position和anchorPoint

回到頂部

一圃酵、隱式動畫屬性

* 在前面幾講中已經(jīng)提到柳畔,每一個UIView內(nèi)部都默認(rèn)關(guān)聯(lián)著一個CALayer,我們可用稱這個Layer為Root Layer(根層)郭赐。所有的非Root Layer薪韩,也就是手動創(chuàng)建的CALayer對象,都存在著隱式動畫捌锭。

* 當(dāng)對非Root Layer的部分屬性進(jìn)行相應(yīng)的修改時俘陷,默認(rèn)會自動產(chǎn)生一些動畫效果,這些屬性稱為Animatable Properties(可動畫屬性)舀锨。

* 列舉幾個常見的Animatable Properties:

bounds:用于設(shè)置CALayer的寬度和高度岭洲。修改這個屬性會產(chǎn)生縮放動畫

backgroundColor:用于設(shè)置CALayer的背景色。修改這個屬性會產(chǎn)生背景色的漸變動畫

position:用于設(shè)置CALayer的位置坎匿。修改這個屬性會產(chǎn)生平移動畫

比如:假設(shè)一開始CALayer的position為(100, 100),然后在某個時刻修改為(200, 200)雷激,那么整個CALayer就會在短時間內(nèi)從(100, 100)這個位置平移到(200, 200)

* 我們也可以從官方文檔中查詢所有的Animatable Properties

1.點(diǎn)擊Window -> Organizer

2.在搜索框輸入"animatable"即可

回到頂部

二替蔬、position和anchorPoint

* position和anchorPoint屬性都是CGPoint類型的

* position可以用來設(shè)置CALayer在父層中的位置,它是以父層的左上角為坐標(biāo)原點(diǎn)(0, 0)

* anchorPoint稱為"定位點(diǎn)"屎暇,它決定著CALayer身上的哪個點(diǎn)會在position屬性所指的位置承桥。它的x、y取值范圍都是0~1根悼,默認(rèn)值為(0.5, 0.5)

1.創(chuàng)建一個CALayer凶异,添加到控制器的view的layer中

1CALayer *myLayer =[CALayer layer];2//設(shè)置層的寬度和高度(100x100)3myLayer.bounds= CGRectMake(0,0,100,100);4//設(shè)置層的位置5myLayer.position= CGPointMake(100,100);6//設(shè)置層的背景顏色:紅色7myLayer.backgroundColor=[UIColor redColor].CGColor;89//添加myLayer到控制器的view的layer中10[self.view.layer addSublayer:myLayer];

第5行設(shè)置了myLayer的position為(100, 100),又因?yàn)閍nchorPoint默認(rèn)是(0.5, 0.5)挤巡,所以最后的效果是:myLayer的中點(diǎn)會在父層的(100, 100)位置

注意剩彬,藍(lán)色線是我自己加上去的,方便大家理解矿卑,并不是默認(rèn)的顯示效果喉恋。兩條藍(lán)色線的寬度均為100。

2.若將anchorPoint改為(0, 0),myLayer的左上角會在(100, 100)位置

1myLayer.anchorPoint= CGPointMake(0,0);

3.若將anchorPoint改為(1, 1)轻黑,myLayer的右下角會在(100, 100)位置

1myLayer.anchorPoint= CGPointMake(1,1);

4.將anchorPoint改為(0, 1)糊肤,myLayer的左下角會在(100, 100)位置

1myLayer.anchorPoint = CGPointMake(0,1);

我想,你應(yīng)該已經(jīng)明白anchorPoint的用途了吧氓鄙,它決定著CALayer身上的哪個點(diǎn)會在position所指定的位置上馆揉。它的x、y取值范圍都是0~1抖拦,默認(rèn)值為(0.5, 0.5)升酣,因此,默認(rèn)情況下蟋座,CALayer的中點(diǎn)會在position所指定的位置上拗踢。當(dāng)anchorPoint為其他值時,以此類推向臀。



CALayer4-自定義層

本文目錄

一巢墅、自定義層的方法1

二、自定義層的方法2

三券膀、其他

自定義層君纫,其實(shí)就是在層上繪圖,一共有2種方法芹彬,下面詳細(xì)介紹一下蓄髓。

回到頂部

一、自定義層的方法1

方法描述:創(chuàng)建一個CALayer的子類舒帮,然后覆蓋drawInContext:方法会喝,使用Quartz2D API進(jìn)行繪圖

1.創(chuàng)建一個CALayer的子類

2.在.m文件中覆蓋drawInContext:方法,在里面繪圖

1@implementation MJLayer23#pragmamark 繪制一個實(shí)心三角形4- (void)drawInContext:(CGContextRef)ctx {5//設(shè)置為藍(lán)色6CGContextSetRGBFillColor(ctx,0,0,1,1);789//設(shè)置起點(diǎn)10CGContextMoveToPoint(ctx,50,0);11//從(50, 0)連線到(0, 100)12CGContextAddLineToPoint(ctx,0,100);13//從(0, 100)連線到(100, 100)14CGContextAddLineToPoint(ctx,100,100);15//合并路徑玩郊,連接起點(diǎn)和終點(diǎn)16CGContextClosePath(ctx);1718//繪制路徑19CGContextFillPath(ctx);20}2122@end

3.在控制器中添加圖層到屏幕上

1MJLayer *layer =[MJLayer layer];2//設(shè)置層的寬高3layer.bounds= CGRectMake(0,0,100,100);4//設(shè)置層的位置5layer.position= CGPointMake(100,100);6//開始繪制圖層7[layersetNeedsDisplay];8[self.view.layer addSublayer:layer];

注意第7行肢执,需要調(diào)用setNeedsDisplay這個方法,才會觸發(fā)drawInContext:方法的調(diào)用译红,然后進(jìn)行繪圖

回到頂部

二预茄、自定義層的方法2

方法描述:設(shè)置CALayer的delegate,然后讓delegate實(shí)現(xiàn)drawLayer:inContext:方法侦厚,當(dāng)CALayer需要繪圖時耻陕,會調(diào)用delegate的drawLayer:inContext:方法進(jìn)行繪圖。

* 這里要注意的是:不能再將某個UIView設(shè)置為CALayer的delegate刨沦,因?yàn)閁IView對象已經(jīng)是它內(nèi)部根層的delegate诗宣,再次設(shè)置為其他層的delegate就會出問題。UIView和它內(nèi)部CALayer的默認(rèn)關(guān)系圖:

1.創(chuàng)建新的層已卷,設(shè)置delegate梧田,然后添加到控制器的view的layer中

1CALayer *layer =[CALayer layer];2//設(shè)置delegate3layer.delegate=self;4//設(shè)置層的寬高5layer.bounds= CGRectMake(0,0,100,100);6//設(shè)置層的位置7layer.position= CGPointMake(100,100);8//開始繪制圖層9[layersetNeedsDisplay];10[self.view.layer addSublayer:layer];

* 在第3行設(shè)置了CALayer的delegate淳蔼,這里的self是指控制器

*注意第9行,需要調(diào)用setNeedsDisplay這個方法裁眯,才會通知delegate進(jìn)行繪圖

2.讓CALayer的delegate(前面設(shè)置的是控制器)實(shí)現(xiàn)drawLayer:inContext:方法

1#pragmamark 畫一個矩形框2- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {3//設(shè)置藍(lán)色4CGContextSetRGBStrokeColor(ctx,0,0,1,1);5//設(shè)置邊框?qū)挾?CGContextSetLineWidth(ctx,10);78//添加一個跟層一樣大的矩形到路徑中9CGContextAddRect(ctx, layer.bounds);1011//繪制路徑12CGContextStrokePath(ctx);13}

回到頂部

三鹉梨、其他

1.總結(jié)

無論采取哪種方法來自定義層,都必須調(diào)用CALayer的setNeedsDisplay方法才能正常繪圖穿稳。

2.UIView的詳細(xì)顯示過程

* 當(dāng)UIView需要顯示時存皂,它內(nèi)部的層會準(zhǔn)備好一個CGContextRef(圖形上下文),然后調(diào)用delegate(這里就是UIView)的drawLayer:inContext:方法逢艘,并且傳入已經(jīng)準(zhǔn)備好的CGContextRef對象旦袋。而UIView在drawLayer:inContext:方法中又會調(diào)用自己的drawRect:方法

* 平時在drawRect:中通過UIGraphicsGetCurrentContext()獲取的就是由層傳入的CGContextRef對象,在drawRect:中完成的所有繪圖都會填入層的CGContextRef中它改,然后被拷貝至屏幕

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末疤孕,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子央拖,更是在濱河造成了極大的恐慌祭阀,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鲜戒,死亡現(xiàn)場離奇詭異专控,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)遏餐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進(jìn)店門伦腐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人失都,你說我怎么就攤上這事柏蘑。” “怎么了粹庞?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵辩越,是天一觀的道長。 經(jīng)常有香客問我信粮,道長,這世上最難降的妖魔是什么趁啸? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任强缘,我火速辦了婚禮,結(jié)果婚禮上不傅,老公的妹妹穿的比我還像新娘旅掂。我一直安慰自己,他們只是感情好访娶,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布商虐。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪秘车。 梳的紋絲不亂的頭發(fā)上典勇,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天,我揣著相機(jī)與錄音叮趴,去河邊找鬼割笙。 笑死,一個胖子當(dāng)著我的面吹牛眯亦,可吹牛的內(nèi)容都是我干的伤溉。 我是一名探鬼主播,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼妻率,長吁一口氣:“原來是場噩夢啊……” “哼乱顾!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起宫静,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤走净,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后囊嘉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體温技,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年扭粱,在試婚紗的時候發(fā)現(xiàn)自己被綠了舵鳞。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡琢蛤,死狀恐怖蜓堕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情博其,我是刑警寧澤套才,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站慕淡,受9級特大地震影響背伴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜峰髓,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一傻寂、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧携兵,春花似錦疾掰、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽炭懊。三九已至,卻和暖如春拂檩,著一層夾襖步出監(jiān)牢的瞬間侮腹,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工广恢, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留凯旋,地道東北人。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓钉迷,卻偏偏與公主長得像至非,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子糠聪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內(nèi)容

  • 在iOS中隨處都可以看到絢麗的動畫效果荒椭,實(shí)現(xiàn)這些動畫的過程并不復(fù)雜,今天將帶大家一窺ios動畫全貌舰蟆。在這里你可以看...
    每天刷兩次牙閱讀 8,471評論 6 30
  • 在iOS中隨處都可以看到絢麗的動畫效果趣惠,實(shí)現(xiàn)這些動畫的過程并不復(fù)雜,今天將帶大家一窺iOS動畫全貌身害。在這里你可以看...
    F麥子閱讀 5,104評論 5 13
  • 本文轉(zhuǎn)載自:http://www.cocoachina.com/ios/20150104/10814.html ...
    idiot_lin閱讀 1,562評論 0 11
  • 轉(zhuǎn)載:http://www.reibang.com/p/32fcadd12108 每個UIView有一個伙伴稱為l...
    F麥子閱讀 6,170評論 0 13
  • 在iOS實(shí)際開發(fā)中常用的動畫無非是以下四種:UIView動畫味悄,核心動畫,幀動畫塌鸯,自定義轉(zhuǎn)場動畫侍瑟。 1.UIView...
    請叫我周小帥閱讀 3,082評論 1 23