1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
//
// NALLabelsMatrix.m
//
// Created by neeks on 04/02/14.
// Copyright (c) 2014 neeks. All rights reserved.
//
#import "NALLabelsMatrix.h"
#define MATRIX_TEXT_FONT [UIFont fontWithName:@"Helvetica" size:12.0]
#define MATRIX_BOARD_COLOR [UIColor colorWithWhite:0.821 alpha:1.0f]
#define MATRIX_TITLE_BG_COLOR [UIColor colorWithWhite:247.0f/255.0f alpha:1.0f]
#define MATRIX_ROW_BG_COLOR [UIColor colorWithRed:249.0f/255.0f green:251.0f/255.0f blue:240.0f/255.0f alpha:1.0f]
@interface NALLabelsMatrix ()
{
NSArray *columnsWidths;
NSUInteger numRows;
NSUInteger dy;
}
// Form Data
@property (strong, nonatomic) NSMutableArray *m_arrRowDatas;
@property (strong, nonatomic) NSMutableArray *m_arrRowHeights;
@property (strong, nonatomic) NSMutableArray *m_arrMatrixLabels;
// Edit Data
@property (strong, nonatomic) NSMutableArray *m_arrDeleteBtns;
@end
@implementation NALLabelsMatrix
#pragma mark - Life Cycle
- (id)initWithFrame:(CGRect)frame andColumnsWidths:(NSArray*)columns {
self = [super initWithFrame:frame];
if (self) {
numRows = 0;
self->columnsWidths = columns;
self->dy = 0;
self->numRows = 0;
self.m_arrRowDatas = [NSMutableArray array];
self.m_arrRowHeights = [NSMutableArray array];
self.m_arrMatrixLabels = [NSMutableArray array];
self.m_bIsEditable = NO;
self.m_arrDeleteBtns = [NSMutableArray array];
}
return self;
}
- (void)didMoveToSuperview {
[super didMoveToSuperview];
if (self.window) {
for (UIView *v in _m_arrDeleteBtns) {
if (v.tag == 0) {
v.hidden = YES;
}
[self.superview addSubview:v];
}
}
else {
[_m_arrDeleteBtns makeObjectsPerformSelector:@selector(removeFromSuperview)];
}
}
- (void)dealloc {
[_m_arrDeleteBtns makeObjectsPerformSelector:@selector(removeFromSuperview)];
}
#pragma mark - Setter
- (void)setM_bIsEditable:(BOOL)bIsEditable {
if (_m_bIsEditable == bIsEditable) {
return;
}
_m_bIsEditable = bIsEditable;
for (UIView *editV in _m_arrDeleteBtns) {
editV.hidden = !_m_bIsEditable;
}
}
#pragma mark - Public Method
- (NSUInteger)rowsCount {
return numRows;
}
- (void)addRecord:(NSArray*)record {
if(record.count != self->columnsWidths.count){
NSLog(@"!!! Number of items does not match number of columns. !!!");
return;
}
CGFloat rowHeight = 30;
CGFloat dx = 0;
NSMutableArray* labels = [NSMutableArray array];
//CREATE THE ITEMS/COLUMNS OF THE ROW
for(NSUInteger i = 0; i < record.count; i++){
float colWidth = [self->columnsWidths[ i ] floatValue]; //colwidth as given at setup
CGRect rect = CGRectMake(dx, dy, colWidth, rowHeight);
//ADJUST X FOR BORDER OVERLAPPING BETWEEN COLUMNS
if(i > 0){
rect.origin.x -= i;
}
//--------------------------------------------
UILabel* col1 = [[UILabel alloc] init];
[col1.layer setBorderColor:[MATRIX_BOARD_COLOR CGColor]];
[col1.layer setBorderWidth:1.0];
col1.font = MATRIX_TEXT_FONT;
col1.frame = rect;
//SET LEFT RIGHT MARGINS & ALIGNMENT FOR THE LABEL
NSMutableParagraphStyle *style =
[[NSParagraphStyle defaultParagraphStyle] mutableCopy];
style.alignment = NSTextAlignmentNatural;
style.headIndent = 10;
style.firstLineHeadIndent = 10.0;
style.tailIndent = -10.0;
//SPECIAL TREATMENT FOR THE FIRST ROW
if(self->numRows == 0){
style.alignment = NSTextAlignmentCenter;
col1.backgroundColor = MATRIX_TITLE_BG_COLOR;
}
else if (self->numRows % 2 == 0) {
style.alignment = NSTextAlignmentCenter;
col1.backgroundColor = MATRIX_ROW_BG_COLOR;
}
else {
style.alignment = NSTextAlignmentCenter;
col1.backgroundColor = [UIColor whiteColor];
}
NSString *text = [NSString stringWithFormat:@"%@", record[ i ]];
NSAttributedString *attrText =
[[NSAttributedString alloc] initWithString:text
attributes:@{ NSParagraphStyleAttributeName : style }];
col1.lineBreakMode = NSLineBreakByCharWrapping;
col1.numberOfLines = 0;
col1.attributedText = attrText;
[col1 sizeToFit];
//USED TO FIND HEIGHT OF LONGEST LABEL
CGFloat h = col1.frame.size.height + 10;
if(h > rowHeight){
rowHeight = h;
}
//MAKE THE LABEL WIDTH SAME AS COLUMN'S WIDTH
rect.size.width = colWidth;
col1.frame = rect;
[labels addObject:col1];
//USED FOR SETTING THE NEXT COLUMN X POSITION
dx += colWidth;
}
// DELETEBTN
UIButton *deleteBtn = [UIButton buttonWithType:UIButtonTypeCustom];
deleteBtn.tag = numRows;
[deleteBtn setImage:[UIImage imageNamed:@"MatrixRowDelete"] forState:UIControlStateNormal];
[deleteBtn addTarget:self
action:@selector(onDeleteAction:)
forControlEvents:UIControlEventTouchUpInside];
deleteBtn.hidden = !_m_bIsEditable;
CGFloat fW = 30.0f;
deleteBtn.frame = (CGRect){
.origin.x = MAX(-2, CGRectGetMinX(self.frame) - fW * .8f),
.origin.y = CGRectGetMinY(self.frame) + dy + (rowHeight - fW) * .5f,
.size.width = fW,
.size.height = fW
};
if (self.superview) {
[self.superview addSubview:deleteBtn];
}
[self.m_arrDeleteBtns addObject:deleteBtn];
//MAKE ALL THE LABELS OF SAME HEIGHT AND THEN ADD TO VIEW
for (UILabel* tempLabel in labels) {
CGRect tempRect = tempLabel.frame;
tempRect.size.height = rowHeight;
tempLabel.frame = tempRect;
[self addSubview:tempLabel];
}
[self.m_arrMatrixLabels addObject:labels];
self->numRows++;
//ADJUST y FOR BORDER OVERLAPPING BETWEEN ROWS
CGFloat fRowH = rowHeight - 1;
[self.m_arrRowHeights addObject:@( fRowH )];
self->dy += fRowH;
//RESIZE THE MAIN VIEW TO FIT THE ROWS
CGRect tempRect = self.frame;
tempRect.size.height = dy;
self.frame = tempRect;
}
- (void)removeRecordAtRow:(NSUInteger)uiRow {
if (uiRow <= 0 || uiRow >= [_m_arrMatrixLabels count]) {
return;
}
NSArray *arrLablesToRemove = _m_arrMatrixLabels[ uiRow ];
CGFloat fRowHeightToRemove = [_m_arrRowHeights[ uiRow ] floatValue];
UIView *deleteBtn = _m_arrDeleteBtns[ uiRow ];
[self.m_arrMatrixLabels removeObjectAtIndex:uiRow];
[self.m_arrRowHeights removeObjectAtIndex:uiRow];
[self.m_arrDeleteBtns removeObjectAtIndex:uiRow];
self->numRows --;
self->dy -= fRowHeightToRemove;
// REMOVE DELETE BTN
[deleteBtn removeFromSuperview];
// REMOVE LABLES
[arrLablesToRemove makeObjectsPerformSelector:@selector(removeFromSuperview)];
// RESIZE LEFT VIEWS
UIColor *bgColor;
CGRect tmpRect;
for (NSUInteger i = uiRow; i < [_m_arrMatrixLabels count]; i ++) {
if(i == 0){
bgColor = MATRIX_TITLE_BG_COLOR;
}
else if (i % 2 == 0) {
bgColor = MATRIX_ROW_BG_COLOR;
}
else {
bgColor = [UIColor whiteColor];
}
NSArray *arrLabels = _m_arrMatrixLabels[ i ];
for (UILabel *col in arrLabels) {
col.backgroundColor = bgColor;
tmpRect = col.frame;
tmpRect.origin.y -= fRowHeightToRemove;
col.frame = tmpRect;
}
UIView *deleteBtn = _m_arrDeleteBtns[ i ];
deleteBtn.tag = uiRow;
tmpRect = deleteBtn.frame;
tmpRect.origin.y -= fRowHeightToRemove;
deleteBtn.frame = tmpRect;
}
//RESIZE THE MAIN VIEW TO FIT THE ROWS
CGRect tempRect = self.frame;
tempRect.size.height = dy;
self.frame = tempRect;
}
#pragma mark - Private Method
- (void)onDeleteAction:(id)sender {
UIButton *btn = sender;
[self removeRecordAtRow:btn.tag];
}
@end