I've been unable to find an answer for this (maybe someone has hacked a solution together).
Is it possible to disable scrolling in a UIScrollView in one direction? I am not talking about disabling vertical or horizontal scrolling, but one direction only. So for example, in a UIScrollView, I want to be able to drag the scrollview in a downwards direction, but not in an upwards direction
Thanks
Turns out a simple solution was actually possible and easy:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView.contentOffset.y > 60) {
[scrollView setContentOffset:CGPointMake(0, 60)];
}
}
This works for me:
-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
scrollView.bounces = YES;
}
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
if (scrollView.contentOffset.y < 0) {
[scrollView setContentOffset:CGPointMake(0, 0)];
scrollView.bounces = NO;
}
if (scrollView.contentOffset.y == 0){
scrollView.bounces = YES;
}
else scrollView.bounces = YES;
}
Fortunately, we can use scrollRectToVisible to avoid jittery behavior after the scroll has been limited:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView.contentOffset.y > 60) {
[scrollView setContentOffset:CGPointMake(0, 60)];
CGFloat pageWidth = scrollView.frame.size.width;
CGFloat pageHeight = scrollView.frame.size.height;
CGRect rect = CGRectMake(0, 0, pageWidth, pageHeight);
[scrollView scrollRectToVisible:rect animated:YES];
}
}
The above solutions will reset you to zero,zero if the user accidentally scrolls vertically. Try this...
- (void)scrollViewDidScroll:(UIScrollView *) scrollView {
if (scrollView.contentOffset.y > 0) {
[scrollView setContentOffset:CGPointMake(scrollView.contentOffset.x, 0)];
}
}
this works for me
static CGPoint lastOffset;
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
scrollView.scrollEnabled = YES;
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
scrollView.scrollEnabled = YES;
lastOffset = scrollView.contentOffset;
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGPoint nowOffset = scrollView.contentOffset;
NSLog(#"delta %f", lastOffset.x - nowOffset.x);
if ((lastOffset.x - nowOffset.x) < 0) {
//uncomment to prevent scroll to left
//scrollView.scrollEnabled = NO;
} else if ((lastOffset.x - nowOffset.x) > 0) {
//uncomment to prevent scroll to right
//scrollView.scrollEnabled = NO;
} else {
scrollView.scrollEnabled = YES;
}
}
If you set the contentSize of the scroller equals to the size of the content, in one of the direction, the scroll will disappear in that direction because there will be nothing to scroll.
It's possible to remove scrolling in vertical direction by setting the scrollView.contentSize height to the same value as scrollView.frame.size.height. Any overflowing content will be hidden. Same can of course be done to restrict vertical scrolling.
An alternative might be:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView.contentOffset.y < 10) {
scrollView.bounces = NO;
}
else scrollView.bounces = YES;
}
But remember that this will only work for the scrollViews, which have a bigger content than their frames.
Instead of using a UIScrollViewDelegate to correct the already wrong contentOffset (which will result in a jittery behaviour) you may want to consider to sub class UIScrollView instead and overriding setContentOffset:
- (void)setContentOffset:(CGPoint)contentOffset {
if (contentOffset.y <= 60) {
[super setContentOffset:contentOffset];
}
}
Off course this can be generalized by adding a property for the min or max allowed value for the content offset. You may need to override setContentOffset:animated: as well.
Turn Off the auto layout. I had the same issues only fixed after disabling auto layout in the content view. Xcode 11 . Automatic -> Translate Masks to Constraints
Related
I have an app which I'm updating to auto layout and size classes and I'm getting some weird behaviour with the label on a button.
The button should be a circle and have a label in the centre. I'm implementing my own subclass so I can reuse it.
Here's the storyboard:
and the code for the class which extends UIButton:
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
[self setBackgroundImage:[UIImage imageNamed:#"selected-green"] forState:UIControlStateHighlighted ];
self.layer.borderColor = [UIColor tlbWhiteColor].CGColor;
self.layer.borderWidth = 10;
}
return self;
}
-(void) layoutSubviews {
self.layer.cornerRadius = self.frame.size.width / 2;
}
With this the appears as expected but there is no label. On debugging I see that the frame of the label has 0 height and width. So I extended layoutSubviews:
-(void) layoutSubviews {
self.layer.cornerRadius = self.frame.size.width / 2;
if (self.titleLabel.frame.size.width == 0) {
[self.titleLabel sizeToFit];
[self setNeedsLayout];
[self layoutIfNeeded];
}
}
The label then appears, but it's in the wrong place:
The only extra info I can offer is that in Reveal the button has weird height and width constraints added:
The titleInsets are all at 0.
Help hugely appreciated.
I don't think you need the layoutSubviews override. I think it's a hack and it's hiding your real issue.
What are the constraints on the 'Go' label? How are you centering it in the UIButton? Also what is the height constraint on the label?
My suggestion would be to put both the UIButton and the Go label inside a container view and centre the label inside the container view. The container view should have the same height and width as the UIButton inside it.
Also are you changing the frames of the views programmatically somewhere in the app? Those weird constraints you talk about in reveal point to that.
As per your requirements:
- (void)viewDidLoad {
[super viewDidLoad];
view_1.layer.cornerRadius = 10; //view_1 is white color
view_1.layer.masksToBounds = YES;
view_2.layer.cornerRadius = _view_2.frame.size.width/2;//view_2 is green color
view_2.layer.masksToBounds = YES;
}
output
Ok, this was a real school boy error.
When the docs said 'The implementation of this method is empty before iOS 6' I for some reason took this to mean there's no need to call super on layoutSubviews.
So the fix was:
-(void) layoutSubviews {
[super layoutSubviews]; // <<<<< THIS WAS MISSING
self.layer.cornerRadius = self.frame.size.width / 2;
self.layer.masksToBounds = YES;
}
I'm looking to do a simple one colour search bar like this:
I've succeeded in doing this in my view controller by setting this image as a background image:
and with this code:
[self.searchBar setTranslucent:NO];
[self.searchBar setSearchFieldBackgroundImage:[UIImage imageNamed:#"searchbg.png"] forState:UIControlStateNormal];
However when I click on the search bar and it goes into the searchdisplaycontroller, it looks like this:
There's a white section there that I can't get rid off. I've tried doing this:
[self.searchDisplayController.searchBar setSearchFieldBackgroundImage:[UIImage imageNamed:#"searchbg.png"] forState:UIControlStateNormal];
But it doesn't seem to work. I'm a bit puzzled as to why they act differently since they're both uisearchbars?
Thanks.
Try setting borderColor and borderWidth for UISearchBar layer it will fix your color change
remember that you have to keep in mind that for ios7 and later view position is different so use as i mentioned below. also i have subclass for UISearchBar, if u want u too create one or replace self by your serachBar
- (void)setup
{
self.placeholder = #"Search Products";
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"7.0")) {
self.backgroundColor = [UIColor lightGrayColor];
UIView *topView = self.subviews[0];
[self searchBarCustomization:topView.subviews];
} else {
self.backgroundImage = [UIImage imageWithColor:[UIColor lightGrayColor]];
self.layer.borderColor = [UIColor lightGrayColor].CGColor;
self.layer.borderWidth = 0.0;
[self searchBarCustomization:self.subviews];
}
}
- (void)searchBarCustomization:(NSArray *)subViews
{
for (UIView *subView in subViews) {
if ([subView isKindOfClass:[UITextField class]]) {
[self customSearchBarField:subView];
}
if ([subView isKindOfClass:[UIButton class]]) {
[self customSearchCancelButton:subView];
}
}
}
- (void)customSearchBarField:(id)searchBarField
{
UITextField *searchField = (UITextField *) searchBarField;
if (!SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"7.0")) {
searchField.background = [UIImage imageWithColor:[UIColor whiteColor]];
searchField.borderStyle = UITextBorderStyleNone;
searchField.layer.cornerRadius = 5.0;
}
}
I followed answer here:
https://stackoverflow.com/a/3233802/3850487
I was able to use #Dave code and it works great.
The only thing is I cannot seem to find a way to change font or size of my label.
[self.rssLabel setText:fullString];
[self.rssLabel setSpeed:0.03f];
[[self rssLabel] setFont:[NSFont boldSystemFontOfSize:100]];//NOT WORKING
Nothing happens at all , it's like it is not being affected.
The closest I got was when I added some code to - (void)drawRect:(NSRect)dirtyRect
- (void)drawRect:(NSRect)dirtyRect {
// Drawing code here.
[[NSColor grayColor] set];//changed the background of the view
NSRectFill(dirtyRect); //not text color
...
}
I tried to contact dave, but I cannot comment yet, please advise.
That's right you need to do the change in drawRect:(NSRect)dirtyRect.
Example:
- (void)drawRect:(NSRect)dirtyRect {
// Drawing code here.
NSFont *font = [NSFont fontWithName:#"Courier" size: 15.0f];
//add more custom stuff, then assign attributes
NSDictionary *attributes = #{ NSFontAttributeName: font};
if (point.x + stringWidth < 0) {
point.x += dirtyRect.size.width;
}
[text drawAtPoint:point withAttributes:attributes];//assign!
if (point.x < 0) {
NSPoint otherPoint = point;
otherPoint.x += dirtyRect.size.width;
[text drawAtPoint:otherPoint withAttributes:attributes];//assign!
}
}
I have an NSScrollView that contains a Drawing. Drawing is a subclass of NSView and is a drop target. I have another class called dragBox which is an NSBox and a drag source. I want to be able to dynamically change the size of the Drawing to accommodate dragging the dragBox outside the size of the NSScrollView. Currently I define a "hot area" in the NSScrollView's content view that automatically scrolls. The problem is that when I drop the dragBox, it doesn't drop it in the virtual space that was just created. It drops it relative to the size of the viewport. Here's the code.
#implementation Drawing
-(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender // validate
{
NSLog(#"Updated");
_drawHintPoint = [sender draggedImageLocation];
if ([sender draggingLocation].x > [[self superview] bounds].size.width - 30)
{
NSRect scrollRect = NSMakeRect(0,0, [self bounds].size.width + 30, [self bounds].size.height) ;
[self setFrame:scrollRect];
_drawHintPoint = NSMakePoint([self bounds].size.width + 30, [sender draggingLocation].y);
[self scrollPoint:_drawHintPoint];
}
return NSDragOperationEvery;
}
-(BOOL) prepareForDragOperation:(id<NSDraggingInfo>)sender
{
NSLog(#"Prepared");
return YES;
}
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender {
NSLog(#"Move Box");
NSPoint pt = _drawHintPoint;
pt.x = pt.x - 32;
pt.y = pt.y - 32;
[[_ico box] setFrameOrigin:pt];
return YES;
}
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender {
NSLog(#"Drag Entered");
_drawHintPoint = NSMakePoint(0, 0);
return NSDragOperationEvery;
}
How do I drop the dragBox so that it drops it in the virtual space provided?
Bruce
Solved!
In draggingUpdated, this did the trick:
_drawHintPoint = [[self superview] convertPoint:[sender draggingLocation] fromView:nil];
You need to convert the dragging location to coordinates in the scroll view. [self superview] in the above line refers to the NSClipRect.
I've got an NSTableView which stretches from edge to edge on my window, but the data in the cells on the edge of the table really need some padding. The window doesn't look good if I leave a gutter on the edges, so I'd like to try to add some padding inside some of the cells so the data isn't right up against the edge.
I can't find anything in Interface Builder or in the code documentation about adding padding or insets to the cells.
Any suggestions?
You can subclass NSTextFieldCell and override the drawInteriorWithFrame:inView: method to custom draw the string.
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
NSRect titleRect = [self titleRectForBounds:cellFrame];
NSAttributedString *aTitle = [self attributedStringValue];
if ([aTitle length] > 0) {
[aTitle drawInRect:titleRect];
}
}
where titleRectForBounds: adds some space
- (NSRect)titleRectForBounds:(NSRect)bounds
{
NSRect titleRect = bounds;
titleRect.origin.x += 5;
titleRect.origin.y += 5;
NSAttributedString *title = [self attributedStringValue];
if (title) {
titleRect.size = [title size];
} else {
titleRect.size = NSZeroSize;
}
// We don't want the width of the string going outside the cell's bounds
CGFloat maxX = NSMaxX(bounds);
CGFloat maxWidth = maxX - NSMinX(titleRect);
if (maxWidth < 0) {
maxWidth = 0;
}
titleRect.size.width = MIN(NSWidth(titleRect), maxWidth);
return titleRect;
}
There's a more full example at http://comelearncocoawithme.blogspot.com/2011/09/custom-cells-in-nstableview-part-1.html
Easy way: add spaces before your text strings.
Better way: embed a view inside your cell and put all other UI objects inside that.
in your cellforrowAtIndexPath you need to implement this.
cell.textLabel.text = [NSString stringWithFormat:#" %#",sometext];
or else
take a label and setframe to it.Then add it to cell