How to Make Custom Drawn Gradient Backgrounds in a Grouped UITableView with Core Graphics
In iPhone app design, it is important to find a balance between customization and familiarity. Many times, subtle differences are all you need to make yourself stand out from the crowd. While doing the Ambiance 3.0 redesign, I wanted something to make my list of content a little different than all the other cookie cutter table views out there.
I found this post on StackOverflow: http://stackoverflow.com/questions/400965/how-to-customize-the-background-border-colors-of-a-grouped-table-view
This was a great resource as it helped me in the right direction — Core Graphics. It was meant as a way to customize the background of a cell before the 3.0 sdk came out, but I used it as a basis for my code to draw a gradient! It needed tweaking and optimization, but after a little bit of hacking away at it, I was able to get it to work nicely. I present to you the UACellBackgroundView .
To use the UACellBackgroundView, simply add the .h and .m files to your project, then use it as the cell background view.
//
// UACellBackgroundView.h
// Ambiance
//
// Created by Matt Coneybeare on 1/31/10.
// Copyright 2010 Urban Apps LLC. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
typedef
enum
{
UACellBackgroundViewPositionSingle
=
0
,
UACellBackgroundViewPositionTop
,
UACellBackgroundViewPositionBottom
,
UACellBackgroundViewPositionMiddle
}
UACellBackgroundViewPosition
;
@interface
UACellBackgroundView
: UIView
{
UACellBackgroundViewPosition
position
;
}
@property
(
nonatomic
)
UACellBackgroundViewPosition
position
;
@end
//
// UACellBackgroundView.m
// Ambiance
//
// Created by Matt Coneybeare on 1/31/10.
// Copyright 2010 Urban Apps LLC. All rights reserved.
//
#define TABLE_CELL_BACKGROUND { 1, 1, 1, 1, 0.866, 0.866, 0.866, 1}
// #FFFFFF and #DDDDDD
#define kDefaultMargin 10
#import "UACellBackgroundView.h"
static
void
addRoundedRectToPath
(
CGContextRef
context
,
CGRect
rect
,
float
ovalWidth
,
float
ovalHeight
);
@implementation
UACellBackgroundView
@synthesize
position
;
-
(
BOOL
)
isOpaque
{
return
NO
;
}
-
(
void
)
drawRect:
(
CGRect
)
aRect
{
// Drawing code
CGContextRef
c
=
UIGraphicsGetCurrentContext
();
int
lineWidth
=
1
;
CGRect
rect
=
[
self
bounds
];
CGFloat
minx
=
CGRectGetMinX
(
rect
),
midx
=
CGRectGetMidX
(
rect
),
maxx
=
CGRectGetMaxX
(
rect
);
CGFloat
miny
=
CGRectGetMinY
(
rect
),
midy
=
CGRectGetMidY
(
rect
),
maxy
=
CGRectGetMaxY
(
rect
);
miny
-=
1
;
CGFloat
locations
[
2
]
=
{
0.0
,
1.0
};
CGColorSpaceRef
myColorspace
=
CGColorSpaceCreateDeviceRGB
();
CGGradientRef
myGradient
=
nil
;
CGFloat
components
[
8
]
=
TABLE_CELL_BACKGROUND
;
CGContextSetStrokeColorWithColor
(
c
,
[[
UIColor
grayColor
]
CGColor
]);
CGContextSetLineWidth
(
c
,
lineWidth
);
CGContextSetAllowsAntialiasing
(
c
,
YES
);
CGContextSetShouldAntialias
(
c
,
YES
);
if
(
position
==
UACellBackgroundViewPositionTop
)
{
miny
+=
1
;
CGMutablePathRef
path
=
CGPathCreateMutable
();
CGPathMoveToPoint
(
path
,
NULL
,
minx
,
maxy
);
CGPathAddArcToPoint
(
path
,
NULL
,
minx
,
miny
,
midx
,
miny
,
kDefaultMargin
);
CGPathAddArcToPoint
(
path
,
NULL
,
maxx
,
miny
,
maxx
,
maxy
,
kDefaultMargin
);
CGPathAddLineToPoint
(
path
,
NULL
,
maxx
,
maxy
);
CGPathAddLineToPoint
(
path
,
NULL
,
minx
,
maxy
);
CGPathCloseSubpath
(
path
);
// Fill and stroke the path
CGContextSaveGState
(
c
);
CGContextAddPath
(
c
,
path
);
CGContextClip
(
c
);
myGradient
=
CGGradientCreateWithColorComponents
(
myColorspace
,
components
,
locations
,
2
);
CGContextDrawLinearGradient
(
c
,
myGradient
,
CGPointMake
(
minx
,
miny
),
CGPointMake
(
minx
,
maxy
),
0
);
CGContextAddPath
(
c
,
path
);
CGPathRelease
(
path
);
CGContextStrokePath
(
c
);
CGContextRestoreGState
(
c
);
}
else
if
(
position
==
UACellBackgroundViewPositionBottom
)
{
CGMutablePathRef
path
=
CGPathCreateMutable
();
CGPathMoveToPoint
(
path
,
NULL
,
minx
,
miny
);
CGPathAddArcToPoint
(
path
,
NULL
,
minx
,
maxy
,
midx
,
maxy
,
kDefaultMargin
);
CGPathAddArcToPoint
(
path
,
NULL
,
maxx
,
maxy
,
maxx
,
miny
,
kDefaultMargin
);
CGPathAddLineToPoint
(
path
,
NULL
,
maxx
,
miny
);
CGPathAddLineToPoint
(
path
,
NULL
,
minx
,
miny
);
CGPathCloseSubpath
(
path
);
// Fill and stroke the path
CGContextSaveGState
(
c
);
CGContextAddPath
(
c
,
path
);
CGContextClip
(
c
);
myGradient
=
CGGradientCreateWithColorComponents
(
myColorspace
,
components
,
locations
,
2
);
CGContextDrawLinearGradient
(
c
,
myGradient
,
CGPointMake
(
minx
,
miny
),
CGPointMake
(
minx
,
maxy
),
0
);
CGContextAddPath
(
c
,
path
);
CGPathRelease
(
path
);
CGContextStrokePath
(
c
);
CGContextRestoreGState
(
c
);
}
else
if
(
position
==
UACellBackgroundViewPositionMiddle
)
{
CGMutablePathRef
path
=
CGPathCreateMutable
();
CGPathMoveToPoint
(
path
,
NULL
,
minx
,
miny
);
CGPathAddLineToPoint
(
path
,
NULL
,
maxx
,
miny
);
CGPathAddLineToPoint
(
path
,
NULL
,
maxx
,
maxy
);
CGPathAddLineToPoint
(
path
,
NULL
,
minx
,
maxy
);
CGPathAddLineToPoint
(
path
,
NULL
,
minx
,
miny
);
CGPathCloseSubpath
(
path
);
// Fill and stroke the path
CGContextSaveGState
(
c
);
CGContextAddPath
(
c
,
path
);
CGContextClip
(
c
);
myGradient
=
CGGradientCreateWithColorComponents
(
myColorspace
,
components
,
locations
,
2
);
CGContextDrawLinearGradient
(
c
,
myGradient
,
CGPointMake
(
minx
,
miny
),
CGPointMake
(
minx
,
maxy
),
0
);
CGContextAddPath
(
c
,
path
);
CGPathRelease
(
path
);
CGContextStrokePath
(
c
);
CGContextRestoreGState
(
c
);
}
else
if
(
position
==
UACellBackgroundViewPositionSingle
)
{
miny
+=
1
;
CGMutablePathRef
path
=
CGPathCreateMutable
();
CGPathMoveToPoint
(
path
,
NULL
,
minx
,
midy
);
CGPathAddArcToPoint
(
path
,
NULL
,
minx
,
miny
,
midx
,
miny
,
kDefaultMargin
);
CGPathAddArcToPoint
(
path
,
NULL
,
maxx
,
miny
,
maxx
,
midy
,
kDefaultMargin
);
CGPathAddArcToPoint
(
path
,
NULL
,
maxx
,
maxy
,
midx
,
maxy
,
kDefaultMargin
);
CGPathAddArcToPoint
(
path
,
NULL
,
minx
,
maxy
,
minx
,
midy
,
kDefaultMargin
);
CGPathCloseSubpath
(
path
);
// Fill and stroke the path
CGContextSaveGState
(
c
);
CGContextAddPath
(
c
,
path
);
CGContextClip
(
c
);
myGradient
=
CGGradientCreateWithColorComponents
(
myColorspace
,
components
,
locations
,
2
);
CGContextDrawLinearGradient
(
c
,
myGradient
,
CGPointMake
(
minx
,
miny
),
CGPointMake
(
minx
,
maxy
),
0
);
CGContextAddPath
(
c
,
path
);
CGPathRelease
(
path
);
CGContextStrokePath
(
c
);
CGContextRestoreGState
(
c
);
}
CGColorSpaceRelease
(
myColorspace
);
CGGradientRelease
(
myGradient
);
return
;
}
-
(
void
)
dealloc
{
[
super
dealloc
];
}
-
(
void
)
setPosition:
(
UACellBackgroundViewPosition
)
newPosition
{
if
(
position
!=
newPosition
)
{
position
=
newPosition
;
[
self
setNeedsDisplay
];
}
}
@end
static
void
addRoundedRectToPath
(
CGContextRef
context
,
CGRect
rect
,
float
ovalWidth
,
float
ovalHeight
)
{
float
fw
,
fh
;
if
(
ovalWidth
==
0
||
ovalHeight
==
0
)
{
// 1
CGContextAddRect
(
context
,
rect
);
return
;
}
CGContextSaveGState
(
context
);
// 2
CGContextTranslateCTM
(
context
,
CGRectGetMinX
(
rect
),
// 3
CGRectGetMinY
(
rect
));
CGContextScaleCTM
(
context
,
ovalWidth
,
ovalHeight
);
// 4
fw
=
CGRectGetWidth
(
rect
)
/
ovalWidth
;
// 5
fh
=
CGRectGetHeight
(
rect
)
/
ovalHeight
;
// 6
CGContextMoveToPoint
(
context
,
fw
,
fh
/
2
);
// 7
CGContextAddArcToPoint
(
context
,
fw
,
fh
,
fw
/
2
,
fh
,
1
);
// 8
CGContextAddArcToPoint
(
context
,
0
,
fh
,
0
,
fh
/
2
,
1
);
// 9
CGContextAddArcToPoint
(
context
,
0
,
0
,
fw
/
2
,
0
,
1
);
// 10
CGContextAddArcToPoint
(
context
,
fw
,
0
,
fw
,
fh
/
2
,
1
);
// 11
CGContextClosePath
(
context
);
// 12
CGContextRestoreGState
(
context
);
// 13
}
Whenever you want to use it, just set the cell's backgroundView to be the UACellBackgroundView in your own UITableViewCell Subclass's initWithStyle method. Then, when you have your data and are creating cells, simply set the position of the cell by calling setPosition, of just call the line directly if you don't want to subclass the UITableViewCell. The position is important as it lets the cell know to draw itself correctly depending on whether or not the cell is first, last, in the middle, or a single cell.
-
(
id
)
initWithStyle:
(
UITableViewCellStyle
)
style
reuseIdentifier:
(
NSString
*
)
identifier
{
if
(
self
=
[
super
initWithStyle:
UITableViewCellStyleSubtitle
reuseIdentifier:
identifier
])
{
// Background Image
self
.
backgroundView
=
[[[
UACellBackgroundView
alloc
]
initWithFrame:
CGRectZero
]
autorelease
];
}
return
self
;
}
-
(
void
)
setPosition:
(
UACellBackgroundViewPosition
)
newPosition
{
[(
UACellBackgroundView
*
)
self
.
backgroundView
setPosition:
newPosition
];
}
Hope this helps you in your quest for a better app. If you want to use it, you will have to set your cell labels and elements to have a clear background, so hopefully you have a fast drawing method and have optimized your table view cells to do minimum work during scrolling.
posted on 2011-04-28 14:41 GaryGaryGary 阅读(189) 评论(0) 收藏 举报
浙公网安备 33010602011771号