UIButton
布局。
– (
void
) showSectionListbyCount:(
float
)totalCount everyColCount:(
float
)paramColCount{
int
curNum=
1
;
int
TotalRow=
ceilf
(totalCount/paramColCount);
//
总行数
for
(
int
curRow=
0
; curRow
for
(
int
curCol=
0
; curCol
//
列数
if
(totalCount
return
;
}
UIButton
*btn=[
UIButton
buttonWithType
:
UIButtonTypeCustom
];
[btn
setFrame
:
CGRectMake
(
10
+(
67
+
10
)*curCol, (
30
+
10
)*curRow,
67
,
30
)];
[btn
setTitle
:[
NSString
stringWithFormat
:
@”%d”
,curNum]
forState
:
UIControlStateNormal
];
[btn
setBackgroundImage
:[
UIImage
imageNamed
:
@”btn_tv_n”
]
forState
:
UIControlStateNormal
];
[btn
setBackgroundImage
:[
UIImage
imageNamed
:
@”btn_tv_h”
]
forState
:
UIControlStateHighlighte
d
];
[btn
setTitleColor
:[
UIColor
blackColor
]
forState
:
UIControlStateNormal
];
[btn
setTitleColor
:[
UIColor
whiteColor
]
forState
:
UIControlStateHighlighte
d
];
[btn
addTarget
:
self
action
:
@selector
(ClickControlAction:)
forControlEvents
:
UIControlEventTouchUpIns
ide
];
[btn
setTag
:curNum];
[
self
.
view
addSubview
:btn];
curNum++;
}
}
}
如果,我们想用表格,那么每个元素可以使用
UITableViewCell
来定义相近的项。
很简单是吧,因为,xCode,为我们提供了这些UI控件供我们使用!所以,我们只需要用!
那么,今天的问题也就来了!如果,我想搞一个能够满足自己的一些UI元素。别急,也就是这样:
比如,我要搞这么一个界面!
我想,首先可以肯定,苹果不可能为我量身定制了这么一个控件。并且,如果,我用苹果的默认控件来写,那么我肯定会崩溃的。。
也就是说,我们将每一项,写成单独的一个UI控件。那么,可以根据数据进行填充!那就酷毙了!
绕了,一大圈,也就是要引用出来今天要学习的,东西!
自定义UI!!!
说起来,很牛X。其实很简单,说白了,就是子类化(重写)
UIView
。
我们常常重写,UIButton,UIImageView,UITableView 等等。因为,可能我们用到的跟这些已有控件很相似,稍微修改一些就能够满足我们。
但是,出入大的时候,我们就不能简单的继承于一个已有控件了!
那就是完全重写!就是子类化
UIView
。
开始动手吧!!!
1.定义一
UIView
个的子类。
这个不解释!
2.重写
drawRect
方法。或者重写
layoutSubviews
方法、
1.
drawRect方法:
– (
void
)drawRect:(
CGRect
)rect
{
// Drawing code
for
(
int
i=
0
; i<<span style=”color: #2f2fd0″>10; i++) {
UIButton
*btn=[
UIButton
buttonWithType
:
UIButtonTypeCustom
];
[btn
setFrame
:
CGRectMake
(
10
,
10
+i*
40
,
67
,
30
)];
[btn
setBackgroundImage
:[
UIImage
imageNamed
:
@”btn_n”
]
forState
:
UIControlStateNormal
];
[btn
setBackgroundImage
:[
UIImage
imageNamed
:
@”btn_h”
]
forState
:
UIControlStateHighlighte
d
];
[btn
addTarget
:
self
action
:
@selector
(ClickControlAction:)
forControlEvents
:
UIControlEventTouchUpIns
ide
];
[btn
setTag
:i];
[
self
addSubview
:btn];
}
}
2.
layoutSubviews 方法
– (
void
)layoutSubviews{
[
super
layoutSubviews
];
[
self
setBackgroundColor
:[
UIColor
clearColor
]];
[
_imgPic
setFrame
:
CGRectMake
(
7
,
6
,
86
,
108
)];
[
_imgPic
setImage
:[
UIImage
imageNamed
:[
self
.
dictData
objectForKey
:
@”img_content”
]]];
[
_imgPic
.
layer
setShouldRasterize
:
NO
];
[
_imgPic
.
layer
setBorderColor
: [[
UIColor
whiteColor
]
CGColor
]];
[
_imgPic
.
layer
setBorderWidth
:
1.0
];
[[
_imgPic
layer
]
setShadowRadius
:
2
];
[[
_imgPic
layer
]
setShadowOpacity
:
1
];
[[
_imgPic
layer
]
setShadowColor
:[
UIColor
blackColor
].
CGColor
];
[[
_imgPic
layer
]
setShadowOffset
:
CGSizeMake
(
0
,
1
)];
[
self
addSubview
:
self
.
imgPic
];
}
可见,这两种方法都可以的。具体的区别,就是
drawRect
方法和
layoutSubviews
方法之间的区别了。
但是,经过测试,我发现,应该使用
drawRect
方法,来完成界面的绘制。因为,如果我们使用的是
layoutSubviews
方法,那么每一次改变frame的时候,
layoutSubviews
都将重新执行。显然不科学。
在网上,我看到,大部分例子使用的是
drawRect方法,来重绘界面。
(绘制界面)
我使用了
layoutSubviews方法。在frame改变时,会自动调用。
(重定向子视图)
根据需要选择使用哪一种方法!
关于两种方法,在网上搜了一下,总结如下:
layoutSubviews在以下情况下会被调用:
1、init初始化不会触发layoutSubviews。
2、addSubview会触发layoutSubviews。
3、设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化。
4、滚动一个UIScrollView会触发layoutSubviews。
5、旋转Screen会触发父UIView上的layoutSubviews事件。
6、改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件。
7、直接调用setLayoutSubviews。
drawRect在以下情况下会被调用:
1、如果在UIView初始化时没有设置rect大小,将直接导致drawRect不被自动调用。drawRect 掉用是在Controller->loadView,
Controller->viewDidLoad
两方法之后掉用的.所以不用担心在 控制器中,这些View的drawRect就开始画了.这样可以在控制器中设置一些值给View(如果这些View
draw的时候需要用到某些变量 值).
2、该方法在调用sizeToFit后被调用,所以可以先调用sizeToFit计算出size。然后系统自动调用drawRect:方法。
3、通过设置contentMode属性值为UIViewContentModeRedraw。那么将在每次设置或更改frame的时候自动调用drawRect:。
4、直接调用setNeedsDisplay,或者setNeedsDisplayInRect:触发drawRect:,但是有个前提条件是rect不能为0。
以上1,2推荐;而3,4不提倡
drawRect方法使用注意点:
1、 若使用UIView绘图,只能在drawRect:方法中获取相应的contextRef并绘图。如果在其他方法中获取将获取到一个invalidate 的ref并且不能用于画图。drawRect:方法不能手动显示调用,必须通过调用setNeedsDisplay
或 者
setNeedsDisplayInRect,让系统自动调该方法。
2、若使用calayer绘图,只能在drawInContext:
中(类似于drawRect)绘制,或者在delegate中的相应方法绘制。同样也是调用setNeedDisplay等间接调用以上方法
3、若要实时画图,不能使用gestureRecognizer,只能使用touchbegan等方法来掉用setNeedsDisplay实时刷新屏幕
3.自定义UIView的初始化方法。
我们常常在
UIViewController
中,看到
initWithNibName
方法:
– (
id
)initWithNibName:(
NSString
*)nibNameOrNil bundle:(
NSBundle
*)nibBundleOrNil
{
self
= [
super
initWithNibName
:nibNameOrNil
bundle
:nibBundleOrNil];
if
(
self
) {
// coding
}
return self
;
}
这是xCode给我们定义好的初始化方法。
既然,我们要自定义UIView,那么最好,根据自己的业务逻辑,来完成子类化UIView的初始化方法:
#pragma mark – Initialization 根据业务逻辑,传入数据,初始化自己
– (
id
)initItemWithFram:(
CGRect
)frame andData:(
NSMutableDictionary
*)paramData{
self
= [
super
initWithFrame
:frame];
if
(
self
) {
// Initialization code
_dictData
=[[
NSMutableDictionary
alloc
]
init
];
_imgPic
=[[
UIImageView
alloc
]
init
];
_imgCover
=[[
UIImageView
alloc
]
init
];
_btnClick
=[[
UIButton
alloc
]
init
];
_btnDel
=[[
UIButton
alloc
]
init
];
_lblTips
=[[
UILabel
alloc
]
init
];
_lblName
=[[
UILabel
alloc
]
init
];
}
self
.
dictData
=paramData;
return self
;
}
+ (
id
) initItemWithFrame:(
CGRect
)frame andData:(
NSMutableDictionary
*)paramData{
WTVTVCollectionItem
*tmpInstance=[[
WTVTVCollectionItem
alloc
]
initItemWithFram
:frame
andData
:paramData];
return
tmpInstance;
}
这样,就可以初始化:
NSMutableArray
*items = [
NSMutableArray
array
];
[items
addObject
:[
WTVTVCollectionItem
initItemWithFrame
:
CGRectMake
(
10
,
10
,
100
,
150
)
andData
:dict]];
[items
addObject
:[
WTVTVCollectionItem
initItemWithFrame
:
CGRectMake
(
10
,
10
,
100
,
150
)
andData
:dict]];
[items
addObject
:[
WTVTVCollectionItem
initItemWithFrame
:
CGRectMake
(
10
,
10
,
100
,
150
)
andData
:dict]];
4.为UIView加入一些动画
动画是UI操作的灵魂!给予动画效果,就看上去有神了。
添加动画,一般也用2种方法:
1.重写UIView的方法,在调用时,进行动画操作。
# pragma mark –
重写父类的
removeFromSuperview
方法,在删除时,使用相应的动画效果
– (
void
) removeFromSuperview {
[
UIView
animateWithDuration
:
0.2
animations
:^{
self
.
alpha
=
0.0
;
[
self
setFrame
:
CGRectMake
(
self
.
frame
.
origin
.
x
+
50
,
self
.
frame
.
origin
.
y
+
50
,
0
,
0
)];
[
_btnDel
setFrame
:
CGRectMake
(
0
,
0
,
0
,
0
)];
}
completion
:^(
BOOL
finished) {
[
super
removeFromSuperview
];
}];
}
2.直接在UIView元素上,进行动画对象的添加
– (
void
) enableEditing {
if
(
self
.
isInEditingMode
==
YES
)
return
;
//
设置为编辑状态
self
.
isInEditingMode
=
YES
;
[
_btnDel
setHidden
:
NO
];
//
开始晃动动画
CATransform3D
transform;
//
获取
0
到
x-1
之间的整数
if
(
arc4random
() %
2
==
1
)
transform =
CATransform3DMakeRotatio
n
(-
0.08
,
0
,
0
,
1.0
);
else
transform =
CATransform3DMakeRotatio
n
(
0.08
,
0
,
0
,
1.0
);
CABasicAnimation
*animation = [
CABasicAnimation
animationWithKeyPath
:
@”transform”
];
animation.
toValue
= [
NSValue
valueWithCATransform3D
:transform];
animation.
autoreverses
=
YES
;
animation.
duration
=
0.1
;
animation.
repeatCount
=
10000
;
animation.
delegate
=
self
;
[[
self
layer
]
addAnimation
:animation
forKey
:
@”wiggleAnimation”
];
[(
WTVTVSprintBoard
*)
self
.
delegate
enableEditingMode
];
}
5.子类化UIView的交互
如何将操作链接起来!?就是说,在控件外,对我们自定义的控件进行操作?!
也有2种方法:
1.消息
2.代理
总结:
我想,我过多的将思路就可以了,因为业务需求不同,控件的自定义需求也不同,所以,不能用具体来固定!但是,思路是想通的,知道了原理,我们就可以发挥我们的聪明智慧,创造出千变万化的控件来!
希望对你有所帮助!!!
回忆一下,这么个场景。
UIButton
布局。
– (
void
) showSectionListbyCount:(
float
)totalCount everyColCount:(
float
)paramColCount{
int
curNum=
1
;
int
TotalRow=
ceilf
(totalCount/paramColCount);
//
总行数
for
(
int
curRow=
0
; curRow
for
(
int
curCol=
0
; curCol
//
列数
if
(totalCount
return
;
}
UIButton
*btn=[
UIButton
buttonWithType
:
UIButtonTypeCustom
];
[btn
setFrame
:
CGRectMake
(
10
+(
67
+
10
)*curCol, (
30
+
10
)*curRow,
67
,
30
)];
[btn
setTitle
:[
NSString
stringWithFormat
:
@”%d”
,curNum]
forState
:
UIControlStateNormal
];
[btn
setBackgroundImage
:[
UIImage
imageNamed
:
@”btn_tv_n”
]
forState
:
UIControlStateNormal
];
[btn
setBackgroundImage
:[
UIImage
imageNamed
:
@”btn_tv_h”
]
forState
:
UIControlStateHighlighte
d
];
[btn
setTitleColor
:[
UIColor
blackColor
]
forState
:
UIControlStateNormal
];
[btn
setTitleColor
:[
UIColor
whiteColor
]
forState
:
UIControlStateHighlighte
d
];
[btn
addTarget
:
self
action
:
@selector
(ClickControlAction:)
forControlEvents
:
UIControlEventTouchUpIns
ide
];
[btn
setTag
:curNum];
[
self
.
view
addSubview
:btn];
curNum++;
}
}
}
如果,我们想用表格,那么每个元素可以使用
UITableViewCell
来定义相近的项。
很简单是吧,因为,xCode,为我们提供了这些UI控件供我们使用!所以,我们只需要用!
那么,今天的问题也就来了!如果,我想搞一个能够满足自己的一些UI元素。别急,也就是这样:
比如,我要搞这么一个界面!
我想,首先可以肯定,苹果不可能为我量身定制了这么一个控件。并且,如果,我用苹果的默认控件来写,那么我肯定会崩溃的。。
也就是说,我们将每一项,写成单独的一个UI控件。那么,可以根据数据进行填充!那就酷毙了!
绕了,一大圈,也就是要引用出来今天要学习的,东西!
自定义UI!!!
说起来,很牛X。其实很简单,说白了,就是子类化(重写)
UIView
。
我们常常重写,UIButton,UIImageView,UITableView 等等。因为,可能我们用到的跟这些已有控件很相似,稍微修改一些就能够满足我们。
但是,出入大的时候,我们就不能简单的继承于一个已有控件了!
那就是完全重写!就是子类化
UIView
。
开始动手吧!!!
1.定义一
UIView
个的子类。
这个不解释!
2.重写
drawRect
方法。或者重写
layoutSubviews
方法、
1.
drawRect方法:
– (
void
)drawRect:(
CGRect
)rect
{
// Drawing code
for
(
int
i=
0
; i<<span style=”color: #2f2fd0″>10; i++) {
UIButton
*btn=[
UIButton
buttonWithType
:
UIButtonTypeCustom
];
[btn
setFrame
:
CGRectMake
(
10
,
10
+i*
40
,
67
,
30
)];
[btn
setBackgroundImage
:[
UIImage
imageNamed
:
@”btn_n”
]
forState
:
UIControlStateNormal
];
[btn
setBackgroundImage
:[
UIImage
imageNamed
:
@”btn_h”
]
forState
:
UIControlStateHighlighte
d
];
[btn
addTarget
:
self
action
:
@selector
(ClickControlAction:)
forControlEvents
:
UIControlEventTouchUpIns
ide
];
[btn
setTag
:i];
[
self
addSubview
:btn];
}
}
2.
layoutSubviews 方法
– (
void
)layoutSubviews{
[
super
layoutSubviews
];
[
self
setBackgroundColor
:[
UIColor
clearColor
]];
[
_imgPic
setFrame
:
CGRectMake
(
7
,
6
,
86
,
108
)];
[
_imgPic
setImage
:[
UIImage
imageNamed
:[
self
.
dictData
objectForKey
:
@”img_content”
]]];
[
_imgPic
.
layer
setShouldRasterize
:
NO
];
[
_imgPic
.
layer
setBorderColor
: [[
UIColor
whiteColor
]
CGColor
]];
[
_imgPic
.
layer
setBorderWidth
:
1.0
];
[[
_imgPic
layer
]
setShadowRadius
:
2
];
[[
_imgPic
layer
]
setShadowOpacity
:
1
];
[[
_imgPic
layer
]
setShadowColor
:[
UIColor
blackColor
].
CGColor
];
[[
_imgPic
layer
]
setShadowOffset
:
CGSizeMake
(
0
,
1
)];
[
self
addSubview
:
self
.
imgPic
];
}
可见,这两种方法都可以的。具体的区别,就是
drawRect
方法和
layoutSubviews
方法之间的区别了。
但是,经过测试,我发现,应该使用
drawRect
方法,来完成界面的绘制。因为,如果我们使用的是
layoutSubviews
方法,那么每一次改变frame的时候,
layoutSubviews
都将重新执行。显然不科学。
在网上,我看到,大部分例子使用的是
drawRect方法,来重绘界面。
(绘制界面)
我使用了
layoutSubviews方法。在frame改变时,会自动调用。
(重定向子视图)
根据需要选择使用哪一种方法!
关于两种方法,在网上搜了一下,总结如下:
layoutSubviews在以下情况下会被调用:
1、init初始化不会触发layoutSubviews。
2、addSubview会触发layoutSubviews。
3、设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化。
4、滚动一个UIScrollView会触发layoutSubviews。
5、旋转Screen会触发父UIView上的layoutSubviews事件。
6、改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件。
7、直接调用setLayoutSubviews。
drawRect在以下情况下会被调用:
1、如果在UIView初始化时没有设置rect大小,将直接导致drawRect不被自动调用。drawRect 掉用是在Controller->loadView,
Controller->viewDidLoad
两方法之后掉用的.所以不用担心在 控制器中,这些View的drawRect就开始画了.这样可以在控制器中设置一些值给View(如果这些View
draw的时候需要用到某些变量 值).
2、该方法在调用sizeToFit后被调用,所以可以先调用sizeToFit计算出size。然后系统自动调用drawRect:方法。
3、通过设置contentMode属性值为UIViewContentModeRedraw。那么将在每次设置或更改frame的时候自动调用drawRect:。
4、直接调用setNeedsDisplay,或者setNeedsDisplayInRect:触发drawRect:,但是有个前提条件是rect不能为0。
以上1,2推荐;而3,4不提倡
drawRect方法使用注意点:
1、 若使用UIView绘图,只能在drawRect:方法中获取相应的contextRef并绘图。如果在其他方法中获取将获取到一个invalidate 的ref并且不能用于画图。drawRect:方法不能手动显示调用,必须通过调用setNeedsDisplay
或 者
setNeedsDisplayInRect,让系统自动调该方法。
2、若使用calayer绘图,只能在drawInContext:
中(类似于drawRect)绘制,或者在delegate中的相应方法绘制。同样也是调用setNeedDisplay等间接调用以上方法
3、若要实时画图,不能使用gestureRecognizer,只能使用touchbegan等方法来掉用setNeedsDisplay实时刷新屏幕
3.自定义UIView的初始化方法。
我们常常在
UIViewController
中,看到
initWithNibName
方法:
– (
id
)initWithNibName:(
NSString
*)nibNameOrNil bundle:(
NSBundle
*)nibBundleOrNil
{
self
= [
super
initWithNibName
:nibNameOrNil
bundle
:nibBundleOrNil];
if
(
self
) {
// coding
}
return self
;
}
这是xCode给我们定义好的初始化方法。
既然,我们要自定义UIView,那么最好,根据自己的业务逻辑,来完成子类化UIView的初始化方法:
#pragma mark – Initialization 根据业务逻辑,传入数据,初始化自己
– (
id
)initItemWithFram:(
CGRect
)frame andData:(
NSMutableDictionary
*)paramData{
self
= [
super
initWithFrame
:frame];
if
(
self
) {
// Initialization code
_dictData
=[[
NSMutableDictionary
alloc
]
init
];
_imgPic
=[[
UIImageView
alloc
]
init
];
_imgCover
=[[
UIImageView
alloc
]
init
];
_btnClick
=[[
UIButton
alloc
]
init
];
_btnDel
=[[
UIButton
alloc
]
init
];
_lblTips
=[[
UILabel
alloc
]
init
];
_lblName
=[[
UILabel
alloc
]
init
];
}
self
.
dictData
=paramData;
return self
;
}
+ (
id
) initItemWithFrame:(
CGRect
)frame andData:(
NSMutableDictionary
*)paramData{
WTVTVCollectionItem
*tmpInstance=[[
WTVTVCollectionItem
alloc
]
initItemWithFram
:frame
andData
:paramData];
return
tmpInstance;
}
这样,就可以初始化:
NSMutableArray
*items = [
NSMutableArray
array
];
[items
addObject
:[
WTVTVCollectionItem
initItemWithFrame
:
CGRectMake
(
10
,
10
,
100
,
150
)
andData
:dict]];
[items
addObject
:[
WTVTVCollectionItem
initItemWithFrame
:
CGRectMake
(
10
,
10
,
100
,
150
)
andData
:dict]];
[items
addObject
:[
WTVTVCollectionItem
initItemWithFrame
:
CGRectMake
(
10
,
10
,
100
,
150
)
andData
:dict]];
4.为UIView加入一些动画
动画是UI操作的灵魂!给予动画效果,就看上去有神了。
添加动画,一般也用2种方法:
1.重写UIView的方法,在调用时,进行动画操作。
# pragma mark –
重写父类的
removeFromSuperview
方法,在删除时,使用相应的动画效果
– (
void
) removeFromSuperview {
[
UIView
animateWithDuration
:
0.2
animations
:^{
self
.
alpha
=
0.0
;
[
self
setFrame
:
CGRectMake
(
self
.
frame
.
origin
.
x
+
50
,
self
.
frame
.
origin
.
y
+
50
,
0
,
0
)];
[
_btnDel
setFrame
:
CGRectMake
(
0
,
0
,
0
,
0
)];
}
completion
:^(
BOOL
finished) {
[
super
removeFromSuperview
];
}];
}
2.直接在UIView元素上,进行动画对象的添加
– (
void
) enableEditing {
if
(
self
.
isInEditingMode
==
YES
)
return
;
//
设置为编辑状态
self
.
isInEditingMode
=
YES
;
[
_btnDel
setHidden
:
NO
];
//
开始晃动动画
CATransform3D
transform;
//
获取
0
到
x-1
之间的整数
if
(
arc4random
() %
2
==
1
)
transform =
CATransform3DMakeRotatio
n
(-
0.08
,
0
,
0
,
1.0
);
else
transform =
CATransform3DMakeRotatio
n
(
0.08
,
0
,
0
,
1.0
);
CABasicAnimation
*animation = [
CABasicAnimation
animationWithKeyPath
:
@”transform”
];
animation.
toValue
= [
NSValue
valueWithCATransform3D
:transform];
animation.
autoreverses
=
YES
;
animation.
duration
=
0.1
;
animation.
repeatCount
=
10000
;
animation.
delegate
=
self
;
[[
self
layer
]
addAnimation
:animation
forKey
:
@”wiggleAnimation”
];
[(
WTVTVSprintBoard
*)
self
.
delegate
enableEditingMode
];
}
5.子类化UIView的交互
如何将操作链接起来!?就是说,在控件外,对我们自定义的控件进行操作?!
也有2种方法:
1.消息
2.代理
总结:
我想,我过多的将思路就可以了,因为业务需求不同,控件的自定义需求也不同,所以,不能用具体来固定!但是,思路是想通的,知道了原理,我们就可以发挥我们的聪明智慧,创造出千变万化的控件来!
希望对你有所帮助!!!