Implementing Grid/table drawing algorithm - ios

I'm trying to implement universal method for generating (drawing) grid formed with UIViews (or other controls). They all should have borders and my problem is I cannot find right algorithm to shift (combine) borders (so the "table" does not have double cell borders like now) and to increase size so the views exactly match given frame (red on picture).
Following code generates picture beneath:
////////
const CGFloat kOuterBorderWidth = 0.0;
const CGFloat kInnerBorderWidth = 1.0;
NSArray *rows;
NSArray *columns = rows = #[#0.065, #0.29, #0.29, #0.29, #0.065];
NSMutableArray *cells = [self drawGridWithFrame:self.frame
columns:columns
rows:rows
outerBorderWidth:kOuterBorderWidth
innerBordersWidth:kInnerBorderWidth];
///////
and the method itself
- (NSMutableArray*)drawGridWithFrame:(CGRect)frame
columns:(NSArray *)columns
rows:(NSArray *)rows
outerBorderWidth:(CGFloat)outerBorderWidth
innerBordersWidth:(CGFloat)innerBordersWidth
{
CGFloat x = 0, y = 0;
NSMutableArray *cells = [NSMutableArray new];
CGFloat height = [rows[0] floatValue] * frame.size.height;
for (int j = 0; j < columns.count; j++) {
CGFloat width = [columns[j] floatValue] * frame.size.width;
CGRect cellFrame = CGRectMake(x, y, width, height);
UIView *cellView = [[UIView alloc] initWithFrame:cellFrame];
cellView.layer.borderWidth = innerBordersWidth;
if (j == 0 || j == columns.count - 1) {
cellView.layer.borderColor = [UIColor magentaColor].CGColor;
}
if (j == 1) {
cellView.layer.borderColor = [UIColor orangeColor].CGColor;
}
if (j == 2) {
cellView.layer.borderColor = [UIColor brownColor].CGColor;
}
[cells addObject:cellView];
x += [columns[j] floatValue] * frame.size.width;
}
return cells;
}

Done it.
Note: outerBorderWidth is now not used here, if it is > 1.0pt, then we additionally should shift views and adjust their size
- (NSMutableArray*)drawGridWithFrame:(CGRect)frame
columns:(NSArray *)columns
rows:(NSArray *)rows
outerBorderWidth:(CGFloat)outerBorderWidth
innerBordersWidth:(CGFloat)innerBordersWidth
{
CGFloat x = 0, y = 0;
NSMutableArray *cells = [NSMutableArray new];
CGFloat heightAdjust = (CGFloat)(rows.count - 1) / (CGFloat)rows.count;
CGFloat widthAdjust = (CGFloat)(columns.count - 1) / (CGFloat)columns.count;
for (int i = 0; i < rows.count; i++) {
CGFloat height = [rows[i] floatValue] * frame.size.height + innerBordersWidth * heightAdjust;
for (int j = 0; j < columns.count; j++) {
CGFloat width = [columns[j] floatValue] * frame.size.width + innerBordersWidth * widthAdjust;
CGRect cellFrame = CGRectMake(x, y, width, height);
UIView *cellView = [[UIView alloc] initWithFrame:cellFrame];
cellView.layer.borderWidth = innerBordersWidth;
if (j == 0 || j == columns.count - 1) {
cellView.layer.borderColor = [UIColor magentaColor].CGColor;
}
if (j == 1) {
cellView.layer.borderColor = [UIColor orangeColor].CGColor;
}
if (j == 2) {
cellView.layer.borderColor = [UIColor brownColor].CGColor;
}
[cells addObject:cellView];
x += width - innerBordersWidth;
}
x = 0;
y += height - innerBordersWidth;
}
return cells;
}
Result:

Related

Change color of chess field after rotate

I newbie in Obj-C.
I have the following chess field:
for (int row = 0; row < 8; row++) {
for (int column = 0; column < 8; column++) {
CGRect square = {horizontalOffSet + (column * squareSize),
verticalOffSet + (row * squareSize),
squareSize, squareSize};
UIView *rect = [[UIView alloc] initWithFrame:square];
rect.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
horizontalOffSet = horizontalOffSet + squareSize;
if ((row + column) % 2 == 0) {
//verticalOffSet = verticalOffSet + squareSize;
horizontalOffSet = 0;
rect.backgroundColor = [UIColor whiteColor];
[anotherRect addSubview:rect];
} else {
//verticalOffSet = verticalOffSet + squareSize;
horizontalOffSet = 0;
rect.backgroundColor = [UIColor blackColor];
[anotherRect addSubview:rect];
}
}
}
My task to change colours of the field when it rotates, for example, fill it with cyan and purple colour when rotating on left. Not clearly understand how to do it.
#somerk check my updated code:
1) I have give identifier(tag) to identified chess view and which has white and which has black color. you can do it without identifier but in case of multiple subviews identifier is better way to get.
int horizontalOffSet = 2;
int squareSize = 40;
int verticalOffSet = 2;
for (int row = 0; row < 8; row++) {
for (int column = 0; column < 8; column++) {
CGRect square = {horizontalOffSet + (column * squareSize),
verticalOffSet + (row * squareSize),
squareSize, squareSize};
UIView *rect = [[UIView alloc] initWithFrame:square];
rect.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
horizontalOffSet = horizontalOffSet + squareSize;
if ((row + column) % 2 == 0) {
//verticalOffSet = verticalOffSet + squareSize;
horizontalOffSet = 0;
rect.tag = 101;
rect.backgroundColor = [UIColor whiteColor];
[self.view addSubview:rect];
} else {
//verticalOffSet = verticalOffSet + squareSize;
rect.tag = 102;
horizontalOffSet = 0;
rect.backgroundColor = [UIColor blackColor];
[self.view addSubview:rect];
}
}
2) I have performed color change event on UIButton click so you have to use that code after rotation event.
-(IBAction)changeColor:(UIButton *)btn{
for(UIView *rectViews in self.view.subviews){
UIColor *clrblck = [UIColor blackColor];
if(rectViews.backgroundColor == clrblck && rectViews.tag == 102){
rectViews.backgroundColor = [UIColor cyanColor];
}else if(rectViews.backgroundColor == clrblck && rectViews.tag == 101){
rectViews.backgroundColor = [UIColor purpleColor];
}else{
// you will get other views here..
}
}
}
I have get all subviews and check backgroundColor and tag and change its backgroundColor.
Note: change view'name according your view's name in loop and where you add rect as subviews in your anotherRect.
Free to ask me if you have any question. Happy Coding :)
Find another possible solution to change colors:
-(void) viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
CGFloat rndmColor1 = (float)(arc4random() % 256) / 255;
CGFloat rndmColor2 = (float)(arc4random() % 256) / 255;
for(UIView *rect in self.chessField.subviews){
if (rect.tag == 102) {
rect.backgroundColor = [UIColor colorWithHue:rndmColor1 saturation:1 brightness:1 alpha:1];
} else if (rect.tag == 101) {
rect.backgroundColor = [UIColor colorWithHue:rndmColor2 saturation:1 brightness:1 alpha:1];
}
}
}

Cropping UIView

I have a view which needs to be cropped. I have 4 views displaying video sub viewed on the main view. Because of the videos ratio, I need to crop the views making the videos squares instead of rectangles. Here is my code:
- (void)videoSize {
CGFloat size;
if ([self.videosView frame].size.height <= [self.emplacementView frame].size.width) {
size = [self.emplacementView frame].size.height;
} else {
size = [self.emplacementView frame].size.width;
}
CGFloat offsetX = 0;
CGFloat offsetY = 0;
NSArray* keys = [mediaStreams allKeys];
int count = keys.count;
if ( !count ) return;
for (int i=0; i<count; i++) {
NSString* id = keys[i];
MediaStream* ms = [ mediaStreams valueForKey:id ];
switch (i) {
case 0:
offsetX = 0;
offsetY = 0;
break;
case 1:
offsetX = size / 2;
offsetY = 0;
break;
case 2:
offsetX = 0;
offsetY = size / 2;
break;
case 3:
offsetX = size / 2;
offsetY = size / 2;
break;
default:
break;
}
CGRect frame = CGRectMake(offsetX, offsetY, size / 2, size / 2);
[ms getVideoView].getView.frame = frame;
[ms getVideoView].getView.backgroundColor = [UIColor greenColor];
}
[self.videosView addSubview:[ [ mediaStream getVideoView ] getView] ];
}
I tried different ways by adding more views to hide them, but it doesn't work at all. If you already have a solution to this problem or an idea to solve it.
Set clipsToBounds property for each of the 4 views displaying video to YES
view1.clipsToBounds = YES;

Display the UILabel verticallly from the NSMutableArray inside the UIView

I have a list of array objects which I pass into to a loop and display it as UILabel dynamically. However I need the values to display it in a vertical. Below are my code,
labelArrays = [NSMutableArray arrayWithObjects:#"One”, #“Two”, #“Three",#"four",#"five",#"six" ,nil];
//inside a method with a loop am passing the array and creating the labels.
-(void) createlabel:(CGRect) frame{
float xCoordinate = frame.origin.x;
float yCoordinate = frame.origin.y;
int labelHeight =30;
int gapBetweenTwoLabels =2;
int labelWidth = 100;
for(int counter = 0; counter < [labelArrays count]; counter++){
UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(xCoordinate,yCoordinate,labelWidth,labelHeight)];
label.text = [labelArrays objectAtIndex:counter];
[self addSubview:label];
xCoordinate = xCoordinate + labelWidth + gapBetweenTwoLabels;
}
}
//frame
[self createlabel:CGRectMake(25,130,100,40)];
This displays me as
one two three four five six
but i need it as
one two three
four five six
can anyone suggest me how can i achieve it? Note: I use this method inside the UIView not in the controller.
Change your y-coordinate as #Larme mentioned
labelArrays = [NSMutableArray arrayWithObjects:#"One”, #“Two”, #“Three", #"four", #"five", #"six" ,nil];
If you want output as following
one
two
three
four
five
six
-(void) createlabel:(CGRect) frame {
CGFloat xCoordinate = frame.origin.x;
CGFloat yCoordinate = frame.origin.y;
CGFloat labelHeight = frame.size.height;
CGFloat labelWidth = frame.size.width;
CGFloat gapBetweenTwoLabels = 2;
for(int counter = 0; counter < [labelArrays count]; counter++) {
UILabel *label = [[UILabel alloc]initWithFrame : CGRectMake(xCoordinate, yCoordinate, labelWidth, labelHeight)];
label.text = [labelArrays objectAtIndex:counter];
[self addSubview:label];
yCoordinate = yCoordinate + labelHeight + gapBetweenTwoLabels;
}
}
But if you want output as :
one
two
three
four
five
six
-(void) createlabel:(CGRect) frame {
CGFloat xCoordinate = frame.origin.x;
CGFloat yCoordinate = frame.origin.y;
CGFloat labelHeight = frame.size.height;
CGFloat labelWidth = frame.size.width;
CGFloat gapBetweenTwoLabels = 2;
for(int counter = 0; counter < [labelArrays count]; counter++) {
UILabel *label = [[UILabel alloc]initWithFrame : CGRectMake(xCoordinate, yCoordinate, labelWidth, labelHeight)];
label.text = [labelArrays objectAtIndex:counter];
[self addSubview:label];
if((counter+1)%3 == 0) {
xCoordinate = 0;
yCoordinate = yCoordinate + labelHeight + gapBetweenTwoLabels;
} else {
xCoordinate = xCoordinate + labelWidth + gapBetweenTwoLabels;
}
}
}
Function call
[self createlabel:CGRectMake(25,130,100,40)];

Draw grid of circles

What would be the best way on iOS to achieve drawing a grid of circles with fixed columns and rows ?. I would want to identify each circle when the user taps on it.
I tried using collection views but it seems CoreGraphics is meant for tasks like these.
You can create buttons dynamically as follows :
- (void)drawSheet
{
int numberOfRow=5;
int numberOfColumn=4;
float x = 1,
y = 20,
padding = 5,
width = (self.view.frame.size.width-(padding*(numberOfColumn-1)))/numberOfColumn,
height = (self.view.frame.size.height-(padding*(numberOfRow-1)))/numberOfRow;
int counter = 0;
for (int i=0; i<numberOfRow; i++) {
for (int j=0; j<numberOfColumn; j++) {
UIButton *btn = [[UIButton alloc]initWithFrame:CGRectMake(x, y, 74, 74)];
btn.layer.cornerRadius = btn.frame.size.width/2;
btn.layer.borderColor = [UIColor grayColor].CGColor;
btn.layer.borderWidth = 2.0;
[btn addTarget:self action:#selector(buttonPress:) forControlEvents:UIControlEventTouchUpInside];
btn.clipsToBounds = YES;
btn.tag = counter;
[self.view addSubview:btn];
x = x + width + padding;
counter = counter + 1;
}
x = 0;
y = y + height + padding;
}
}
When you tap on it, you will get tag of it :
- (IBAction)buttonPress:(UIButton *)sender{
NSLog(#"%ld",sender.tag);
}
hi Please check the below code. i have added 3 circles in a row, you could use more if you want.
- (void)viewDidLoad {
[super viewDidLoad];
UIView *circleView;
int x = 10;
int y = 20;
static int tagNum = 0;
for (int row=0; row < 5;) {
for (int cirNum =0 ; cirNum <3;) {
circleView = [[UIView alloc] initWithFrame:CGRectMake(x,y,100,100)];
circleView.alpha = 0.5;
circleView.layer.cornerRadius = 50;
circleView.backgroundColor = [UIColor blueColor];
circleView.tag = tagNum;
NSLog(#"tagNum is %d", tagNum);
[self.view addSubview:circleView];
cirNum ++;
x = x + 100;
tagNum ++;
//y = y + 20;
}
row++;
y = y + 100;
x = 10;
}
// Do any additional setup after loading the view, typically from a nib.
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint location = [[touches anyObject] locationInView:self.view];
CGRect fingerRect = CGRectMake(location.x-5, location.y-5, 10, 10);
for(UIView *view in self.view.subviews){
CGRect subviewFrame = view.frame;
if(CGRectIntersectsRect(fingerRect, subviewFrame)){
//we found the finally touched view
//NSLog(#"Yeah !, i found it %#",view);
NSLog(#"view tag touched is %ld",view.tag);
}
}
}
output would look like this

Custom UIPageControl dots are misplaced on load

I have a weird behavior with custom UIPageControl.
I subclassed it and in setCurrentPage method I draw custom dots.
In iOS 6 on load they just miss.
In iOS 7 the dots are misplaced.
In both iOS's dots are being positioned correctly only after I change the slide.
I tried the following methods without success:
[customPageControl updateCurrentPageDisplay];
[customPageControl updateConstraints];
[customPageControl sizeToFit];
[customPageControl.currentPage = 1];
The code:
#implementation ProfilePagesPageControl
#synthesize originalSubviews;
#synthesize dotsHeight;
- (void)setCurrentPage:(NSInteger)page
{
[super setCurrentPage:page];
[self updateDots];
}
- (void)updateDots
{
for (int i = 0; i < self.subviews.count; i++)
{
UIView* dotView = [self.subviews objectAtIndex:i];
for (int j = dotView.subviews.count - 1; j >= 0; j--)
{
UIView *view = [dotView.subviews objectAtIndex:j];
[view removeFromSuperview];
}
int widthForDots = [Utils getDeviceBounds].width - Constraints.Gap * 3;
int effectiveWidth = widthForDots / self.subviews.count - Constraints.Gap;
int effectiveGap = (widthForDots - (effectiveWidth * self.subviews.count) + Constraints.Gap * 3) / self.subviews.count;
int effectiveHeight = dotsHeight;
if (i == self.currentPage)
effectiveHeight = effectiveHeight + 3;
else
effectiveHeight = effectiveHeight - 3;
CGRect dotViewFrame = dotView.frame;
dotViewFrame.origin.x = effectiveWidth * i + Constraints.Gap + effectiveGap * i;
dotViewFrame.origin.y = self.frame.size.height / 2 - effectiveHeight / 2;
dotViewFrame.size.width = effectiveWidth;
dotViewFrame.size.height = effectiveHeight;
dotView.frame = dotViewFrame;
UIView *dotSubView = [[UIView alloc] initWithFrame:CGRectMake(0,
0,
dotView.frame.size.width,
dotView.frame.size.height)];
if (i == self.currentPage)
dotSubView.backgroundColor = [UIColor blackColor];
else
dotSubView.backgroundColor = [UIColor grayColor];
[UIUtils roundCorner:(UIRectCornerTopLeft | UIRectCornerTopRight | UIRectCornerBottomLeft | UIRectCornerBottomRight) forView:dotSubView];
ProfileSlideView *slideView = [self.originalSubviews objectAtIndex:i];
RevUILabel *label = [[RevUILabel alloc] initWithSize:13];
label.text = slideView.name;
label.frame = CGRectMake(dotSubView.frame.size.width / 2 - label.frame.size.width / 2,
dotSubView.frame.size.height / 2 - label.frame.size.height / 2,
label.frame.size.width,
label.frame.size.height);
[dotSubView addSubview:label];
[dotView addSubview:dotSubView];
}
}
#end
The iOS7 look:
The iOS6 look:
:
After slide look:
Make sure you call updateDots somewhere else (such as viewDidLoad, or viewWillAppear) so they can be set up before you switch any pages. If you only call updateDots in setCurrentPage it will only be called once you switch the page the first time.

Resources