Context:
I am building a chat app, I used code from apple sample.
It looks exactly like the native message app. My issue is on the iPad version I am implementing.
Here's an image:
As you can see in the image, I need it the righ ballon to be on the right edge of the screen
I track down the code, and I narrow down the block of code that needs tweaking.
// Comput the X,Y origin offsets
CGFloat xOffsetLabel;
CGFloat xOffsetBalloon;
CGFloat yOffset;
if (TRANSCRIPT_DIRECTION_SEND == transcript.direction) {//
// Sent messages appear or right of view
xOffsetLabel = 320 - labelSize.width - (BALLOON_WIDTH_PADDING / 2) - 3;
xOffsetBalloon = 320 - balloonSize.width;
yOffset = BUFFER_WHITE_SPACE / 2;
_nameLabel.text = #"";
// Set text color
_messageLabel.textColor = [UIColor whiteColor];
// Set resizeable image
_balloonView.image = [self.balloonImageRight resizableImageWithCapInsets:_balloonInsetsRight];
}
else {
// Received messages appear on left of view with additional display name label
xOffsetBalloon = 0;
xOffsetLabel = (BALLOON_WIDTH_PADDING / 2) + 3;
yOffset = (BUFFER_WHITE_SPACE / 2) + nameSize.height - NAME_OFFSET_ADJUST;
if (TRANSCRIPT_DIRECTION_LOCAL == transcript.direction) {
_nameLabel.text = #"user";
}
else {
_nameLabel.text = #"Admin"; //nameText;
}
// Set text color
_messageLabel.textColor = [UIColor darkTextColor];
// Set resizeable image
_balloonView.image = [self.balloonImageLeft resizableImageWithCapInsets:_balloonInsetsLeft];
}
// Set the dynamic frames
_messageLabel.frame = CGRectMake(xOffsetLabel, yOffset + 5, labelSize.width, labelSize.height);
_balloonView.frame = CGRectMake(xOffsetBalloon, yOffset, balloonSize.width, balloonSize.height);
_nameLabel.frame = CGRectMake(xOffsetLabel - 2, 1, nameSize.width, nameSize.height);
Unfortunately my attempts to place green ballon to the right were unsuccessful(I can only more the content of the text to the right not the ballon itself). any idea ?
Here:
xOffsetLabel = 320 - labelSize.width - (BALLOON_WIDTH_PADDING / 2) - 3;
xOffsetBalloon = 320 - balloonSize.width;
320 is the width of the iPhone screen. That needs to be changed to the width of the iPad (either 1024 or 768 depending on the orientation).
Of course your view also needs to be as wide as the iPad screen, so make sure that that's resized too.
Tim
Related
I have a UIView that displays like a bar and its width should change based on a NSNumber value displayed on a UILabel.
Image below shows the ui
For instance: As shown in the image, all 3 orange bars have different values. I need the bar's width should also be different based on the value. The bars with value 14 and 10 should be less in width than the bar with value 18.
Following is the code I wrote but it doesn't work.
//Get the value as string
NSString *countString = cell.numberOfTuneIn.text;
//MAximum size of the bar
CGSize maxSize = CGSizeMake(cell.numberOfTuneIn.bounds.size.width, CGFLOAT_MAX);
CGRect s = [countString boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:#{NSFontAttributeName:cell.numberOfTuneIn.font} context:nil];
//set the frame of the bar
CGRect rect = cell.barView.frame;
rect.size.width = s.size.width;
cell.barView.frame = rect;
Can someone please help with:
How do I change the width of the bar based on the value?
This is the basic logic you should follow:
Get bar number range (e.g. 0-100)
Get width pixel range (e.g. 0-320)
Create ratio (e.g. 320 / 100) or 3.2 pixels of width for each 1 you
increment...
So according to the example above:
If the bar is 100, it's width is 100 * 3.2 = 320 px width
If the bar is 50, it's width is 50 * 3.2 = 160 px width
Hope it helped.
- (CGFloat)getViewlWidth:(float)labelValue {
// Setup view bar settings, you can take those settings outside of this method if needed
int maxLabelValue = 100;
int viewMaxWidth = 320; // You can make it dynamic according to screen width
float widthPixelRatio = viewMaxWidth / maxLabelValue;
// Calculate width
CGFloat pixelsResult = labelValue * widthPixelRatio;
// Return value
return pixelsResult;
}
// Lets assume that here you get the label value from the server and you called it labelValue
NSString * labelValue = // Value from server
/*
Create UILabel here, showing the value from server
*/
// Get the width of the UIView to be
CGFloat myViewWidth = [self getViewlWidth:[labelValue floatValue]];
/*
Create the UIView here and set its witdh to the result of the CGFloat above (myViewWidth)
*/
I am trying to do something whatsapp like for messages for having a cell that resizes based on contentsize and in the bottom right corner to have the date... the problem is that I don't know the rectangle position for the excluded path because the text is dynamic and I have something like this but works only for multiple lines, but not for a single line:
NSString *txt=#"I'm writing ";//a text renderer using Core Text, and I discovered I’ll need to wrap text around objects (such as is done in any DTP program). I couldn’t find any easy answers as to how to do this in the documentation, so having finally got it working I’ll share what I did. To lay out text in a custom shape in Core Text, you can pass a CGPath in when you create your CTFramesetterRef. Originally this only supported rectangular paths, but now it supports fully custom paths. My first thought was to see if I could subtract the region to wrap around from the path for my frame’s border, and pass the result in to Core Text as a path. It turns out firstly that subtracting one path from another in Core Graphics is not trivial. However, if you simply add two shapes to the same path, Core Graphics can use a winding rule to work out which areas to draw. Core Text, at least as of iOS 4.2, can also use this kind of algorithm. This will work for many cases: if you can guarantee that your object to be wrapped will be fully inside the frame (and not overlapping the edge), just go ahead and add its border to the same path as your frame, and Core"; // Text will do the rest.";
txtText.text=txt;
CGSize textFrame = [txtText sizeThatFits:CGSizeMake(235, MAXFLOAT)];
UIBezierPath * imgRect = [UIBezierPath bezierPathWithRect:CGRectMake(textFrame.width-35, textFrame.height-20, 35, 20)];
txtText.textContainer.exclusionPaths = #[imgRect];
textFrame = [txtText sizeThatFits:CGSizeMake(235, MAXFLOAT)];
//int frameWidth=375;
txtText.frame=CGRectIntegral(CGRectMake(10, 10, textFrame.width, textFrame.height));
lblHour.frame=CGRectIntegral(CGRectMake(textFrame.width-35, textFrame.height-15, 35, 20));
viewCanvasAround.frame=CGRectIntegral(CGRectMake(50, 100, textFrame.width+20, textFrame.height+20));
I had the same problem too. I added attributedString with textAttachment which it has a size. You will set an estimated maximum size. There's no problem with a single line either.
(Sorry, I am not good at English.)
This is the sample code.
var text: String! {
didSet {
let font = UIFont.systemFont(ofSize: 13);
let att = NSMutableAttributedString.init(string: text, attributes: [NSAttributedString.Key.foregroundColor : UIColor.black,
NSAttributedString.Key.font : font]);
let attachment = NSTextAttachment.init(data: nil, ofType: nil);
var size = extraSize;
size.height = font.lineHeight;
attachment.bounds = CGRect.init(origin: CGPoint.init(), size: size);
att.append(NSAttributedString.init(attachment: attachment));
textView.attributedText = att;
}
}
There is a nice solution my colleague found in actor.im. https://github.com/actorapp/actor-platform/blob/master/actor-sdk/sdk-core-ios/ActorSDK/Sources/Controllers/Content/Conversation/Cell/AABubbleTextCell.swift#L312
let container = YYTextContainer(size: CGSizeMake(maxTextWidth, CGFloat.max))
textLayout = YYTextLayout(container: container, text: attributedText)!
// print("Text Layouted")
// Measuring text and padded text heights
let textSize = textLayout.textBoundingSize
if textLayout.lines.count == 1 {
if textLayout.textBoundingSize.width < maxTextWidth - timeWidth {
//
// <line_0> <date>
//
bubbleSize = CGSize(width: textSize.width + timeWidth, height: textSize.height)
} else {
//
// <line_________0>
// <date>
//
bubbleSize = CGSize(width: textSize.width, height: textSize.height + 16)
}
} else {
let maxWidth = textSize.width
let lastLine = textLayout.lines.last!.width
if lastLine + timeWidth < maxWidth {
//
// <line_________0>
// <line_________1>
// ..
// <line_n> <date>
//
bubbleSize = textSize
} else if lastLine + timeWidth < maxTextWidth {
//
// |------------------|
// <line______0>
// <line______1>
// ..
// <line______n> <date>
//
bubbleSize = CGSize(width: max(lastLine + timeWidth, maxWidth), height: textSize.height)
} else {
//
// <line_________0>
// <line_________1>
// ..
// <line_________n>
// <date>
//
bubbleSize = CGSize(width: max(timeWidth, maxWidth), height: textSize.height + 16)
}
}
I had the same problem (for me it was a button in right corner) and there is the way how I resolved it:
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
[self updateTextExclusionPaths];
}
- (void)updateTextExclusionPaths {
// Remove old exclusionPaths to calculate right rects of new
textView.textContainer.exclusionPaths = #[];
// Force textView to layout the text without exclusionPaths
[textView.layoutManager glyphRangeForTextContainer:textView.textContainer];
/// Because of some specifics of my implementation I had a problem with wrong frame of my button. So I calculated it manually
// Calculate new exclusionPaths
CGRect buttonFrameInTextView = [superViewOfTextView convertRect:button.frame toView:textView];
// Calculate textView.text size without any exclusionPaths to calculate right button frame
CGSize textViewSize = [textView sizeThatFits:CGSizeMake(textView.frame.size.width, CGFLOAT_MAX)];
// Update Y position of button
buttonFrameInTextView.origin.y = size.height - buttonFrameInTextView.size.height;
// Add new exclusionPaths
UIBezierPath *buttonRectBezierPath = [UIBezierPath bezierPathWithRect:buttonFrameInTextView];
textView.textContainer.exclusionPaths = #[ buttonRectBezierPath ];
}
I'm trying to implement a bar chart into my iOS app. I am using JBChartView. Everything is working fine, but there is no colour to the bars except when I press on them using the touchEvent.
Does anyone have any experience with this particular plugin to help me get it working correctly?
Thanks
- (void)viewDidLoad
{
_barChartView = [[JBBarChartView alloc] init];
_barChartView.delegate = self;
_barChartView.dataSource = self;
_tableView.backgroundColor =[UIColor clearColor];
_barChartView.frame = CGRectMake(0,0,200,200);
_barChartView.backgroundColor = [UIColor clearColor];
[_barChartView reloadData];
[_barChart addSubview: _barChartView];
}
- (UIColor *)barSelectionColorForBarChartView:(JBBarChartView *)barChartView
{
return [UIColor greenColor]; // color of selection view
}
- (BOOL)slideNavigationControllerShouldDisplayLeftMenu
{
return YES;
}
- (UIColor *)barChartView:(JBBarChartView *)barChartView colorForBarViewAtIndex:(NSUInteger)index
{
return [UIColor greenColor];
}
- (NSUInteger)numberOfBarsInBarChartView:(JBBarChartView *)barChartView
{
return 4;
}
- (CGFloat)barChartView:(JBBarChartView *)barChartView heightForBarViewAtAtIndex:(NSUInteger)index
{
return 100.0;
}
The problem appears to be with how JBBarChartView "normalizes" the values. Per the header file for JBBarChartView.h:
/**
* Height for a bar at a given index (left to right). There is no ceiling on the the height;
* the chart will automatically normalize all values between the overal min and max heights.
*
* #param barChartView The bar chart object requesting this information.
* #param index The 0-based index of a given bar (left to right, x-axis).
*
* #return The y-axis height of the supplied bar index (x-axis)
*/
Because of this "normalization" when all of your values are the same (100.0f) it normalizes them all to 0, so there is no bar to display. Luckily, it is open-source, so you just need to open up the implementation file and make a little modification:
- (CGFloat)normalizedHeightForRawHeight:(NSNumber*)rawHeight
{
CGFloat minHeight = [self minimumValue];
CGFloat maxHeight = [self maximumValue];
CGFloat value = [rawHeight floatValue];
if ((maxHeight - minHeight) <= 0)
{
return self.availableHeight; // change this line to return the max height instead of 0
}
return ((value - minHeight) / (maxHeight - minHeight)) * [self availableHeight];
}
The correct solution to your problem is to supply a minimum value on the chart.
Please look # the documentation for JBChartView:
/**
* The minimum and maxmimum values of the chart.
* If no value(s) are supplied:
*
* minimumValue = chart's data source min value.
* maxmimumValue = chart's data source max value.
*
* If value(s) are supplied, they must be >= 0, otherwise an assertion will be thrown.
* The min/max values are clamped to the ceiling and floor of the actual min/max values of the chart's data source;
* for example, if a maximumValue of 20 is supplied & the chart's actual max is 100, then 100 will be used.
*
* For min/max modifications to take effect, reloadData must be called.
*/
#property (nonatomic, assign) CGFloat minimumValue;
#property (nonatomic, assign) CGFloat maximumValue;
If all of your data is equal to a single value (ie. 100), supplying a minimum value of 0 will ensure all bars are drawn at equal (visible) height (in relation to 0).
Hope this helps.
Please, help me study objective-c!
My program takes a screenshot of whole UIWebView content, saves it, and supposed to display it.
It works fine, until it meets a very long page. Seems like the height of a page is an issue, since it displays 5 Mb screenshots just fine, as long as they are not too long (don't have to much height), however 1Mb but extremely long screenshots do not display in the UIImageView at all. It displays the UIImageView's background and that's it.
My code, attempts to resize the page to be maximum 2000 in height, and minimum 75% of the whole screen size. Aspect ratio is secondary. However, the image is still missing:
- (void)viewDidLoad
{
[super viewDidLoad];
CGFloat divider = 2;
CGFloat imageDisplayLimit = 2000;
CGFloat width = _image.size.width;
CGFloat height = _image.size.height;
//determine the leading parameter (just in case of a fat-S image)
if (width > imageDisplayLimit || height > imageDisplayLimit) {
if (width > height) {
divider = width / imageDisplayLimit;
} else {
divider = height / imageDisplayLimit;
}
}
//don't let it get too fat
CGFloat minimumWidth = self.view.frame.size.width / 1.5;
if (width / divider < minimumWidth) {
width = minimumWidth;
} else {
width /= divider;
}
//don't let it get too long
CGFloat minimumHeight = self.view.frame.size.height / 1.5;
if (height / divider < minimumHeight) {
height = minimumHeight;
} else {
height /= divider;
}
_imageView = [[UIImageView alloc] initWithImage:_image];
_imageView.frame = CGRectMake(0, 0, width, height);
//now just to make it obvious - red background
_imageView.backgroundColor = [UIColor redColor];
_imageView.frame = CGRectMake(0, 0, _image.size.width / divider, _image.size.height / divider);
_imageView.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin);
_imageView.contentMode = UIViewContentModeScaleAspectFill;
[_scrollView addSubview:_imageView];
_scrollView.contentSize = _imageView.bounds.size;
_scrollView.delegate = self;
//just to make scroll visible during debug
_scrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
...
At this point nothing shows, but the red background on a scrollable view.
I'm studying objective-c and don't know A LOT, but I was trying to find a solution for 2 days now. Please, save me!
My guess is aspect fill or fit doesn't do anything just because they don't actually change the image - just a display. What I really should be using (IMHO) is the UIGraphicsBeginImageContext. But I simply don't know how to make it shrink to max 2000 px. I am able to cut it by using
UIGraphicsBeginImageContext(someSizeWith2000Height)
[originalImage drawInRect:CGRectMake(resized_x, resized_y, resized_width, resized_height)];
UIImage* resized_image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
or something like that, but I don't wanna cut it - just shrink (or stretch if too short).
Any ideas? I've run out of those.
Well, since stackoverflow's system is so great, it drops questions between the desks and none can find them, I had to give up on this problem, and the only solution I could come up with is replace UIImageView with UIWebView as an image-displaying view. It makes the image displayed with TERRIBLE quality, but at least it is displayed.
Please, if anyone finds this question by chance and can help.... help! :)
I have a vertical scrollview with thumbnail images to act as a "side panel" for specific items on an ipad app.
Here's my code to set the content size:
- (void)setScrollViewContentSize:(UIScrollView*)scrollView{
NSInteger viewCount = [scrollView.subviews count];
NSLog(#"viewCount: %d", viewCount);
NSLog(#"height: %f", (viewCount * 190.0f));
scrollView.contentSize = CGSizeMake( scrollView.superview.frame.size.width, (viewCount * 190.0f));
}
When I run my app, there's one menu that has 57 items, so the viewCount log shows up as 57 and the height shows up as 10830. On another menu, I have 13 items and thus, the height is 2470.
Everything seems fine here, but when I scroll to the end of the view, the menu with 57 icons has way too much white space left over whereas the menu with 13 items ends perfectly on the last item with a little margin (each thumbnail is 183px). I'm trying to find out what the cause is, but it seems like the more menu items I have, the bigger the scroll view's spacing at the last item gets.
I tried calling scrollView sizeToFit and even trying to create a CGRect of a visible region to apple to my frame, but none of those worked. Any ideas?
thank you.
from https://stackoverflow.com/a/14852596/1363779
float sizeOfContent = 0;
UIView *lLast = [scrollView.subviews lastObject];
NSInteger wd = lLast.frame.origin.y;
NSInteger ht = lLast.frame.size.height;
sizeOfContent = wd+ht;
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width, sizeOfContent);
This is a nice and easy way to do it.
Swift 2.0 version
var sizeOfContent: CGFloat = 0
let lLast: UIView = scrollView.subviews.last!
let wd: CGFloat = lLast.frame.origin.y
let ht: CGFloat = lLast.frame.size.height
sizeOfContent = wd + ht
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width, sizeOfContent)