I am trying to scroll on main uiwebview and when it end scrolling, I want to update that scrolling offset to other uiwebview. I can do that successfully by this.
-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
//user will drag the file and stop on the spot..no deceleration
if(scrollView == self.showPdfWebview.scrollView && !decelerate)
{
NSLog(#"Offset value in scrollViewDidEndDragging is %#",NSStringFromCGPoint(self.showPdfWebview.scrollView.contentOffset));
[[pdfOn scrollView] setContentOffset:CGPointMake(0, self.showPdfWebview.scrollView.contentOffset.y) animated:YES];
self.testLabel.text= [NSString stringWithFormat:#"Offset value in scrollViewDidEndDragging is %#. Offset value of pdfon is %#. Frame of showpdfwebview is %#. Frame of pdfOn is %#",NSStringFromCGPoint(showPdfWebview.scrollView.contentOffset),NSStringFromCGPoint(pdfOn.scrollView.contentOffset),NSStringFromCGRect(showPdfWebview.frame),NSStringFromCGRect(pdfOn.frame)];
}}
However, there is one problem. My main uiwebview frame and other uiwebview frame size is different. As a result, I think scrolling on my main webview and on other webview is different.If I scroll a lot on my main uiwebview, it scroll only a little on other webview.
I got output like this. So, it is wrong. I would like to know how to solve.
They should be same >> Offset value in scrollViewDidEndDragging is {0,1374}. Offset value of pdfon is (0,565).
Frame of showpdfwebview is {{0,50}, {1024,698}}. Frame of pdfon is {{0,0},{1920,1080}}
scrollViewDidEndDragging: is just one of the available delegate methods and the scroll view content offset will often continue to change after it has been called (see the decelerate parameter). So, consider using one of the other methods instead.
Also, if you want a proportional change then you should calculate the percentage offset of the first view and apply that to the second (divide the content offset by the height of v1 and then multiply by the height of v2 to get the v2 content offset).
Related
I'm building a view that's very similar to the messages app - I have a subview at the bottom of the page with a UITextView in it and as the user types and reaches the end of the line the text view as well as the view containing it should expand upward.
The way I have it working is that in the textViewDidChange: method I call my layout function, and that does
CGFloat textViewWidth = 200;
CGFloat textViewHeight = [self.textView sizeThatFits:CGSizeMake(textViewWidth, 2000)].height;
[self resizeParentWithTextViewSize:CGSizeMake(textViewWidth, textViewHeight)];
// And then the resize parent method eventually calls
textView.frame = CGRectMake(10, 10, textViewWidth, textViewHeight);
The problem is that when typing at the end of line and the view expands, I end up with an arbitrary contentOffset.y of something like 10.5 on the text view so the text is all shifted up to the top of the view. Weirdly, it's alternating on every other line, so expanding the first time leaves the y content offset shifted up, then at the next line it's close to zero, then back to 10.5 on the next line, etc. (not sure if that's helpful or just a strange artifact of my values). I can set it back to zero afterwards but it looks terrible because there's a brief flash where the text has the offset value and then it gets shifted back to the middle.
I've read that it's usually better to use content insets for scroll views rather than changing the frame, but I don't get how to do that because I do need to change the frame size as well.
How can I resize the UITextView without this happening? I think I can get by with setting the text view not to be scrollable and that fixes the issue, but I'd like to understand what's going on.
The problem is that UITextView's scroll animation and your frame setting action were happened at the same time.
UITextView internally scrolls the texts you currently typing to visible when typed one more character at the end of the line or typed the new line character. But the scroll animation does not need because you are expanding the textview. Unfortunately we can't control textview's internal scroll action so the text scrolls to the top of the expanded textview weirdly. And that weird scroll makes unnecessary bottom padding too.
You can avoid this weird action very simply with overriding UITextView's setContentOffset:animated: like this.
Objective-C
- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated {
[super setContentOffset:contentOffset animated:NO];
}
Swift
override func setContentOffset(_ contentOffset: CGPoint, animated: Bool) {
super.setContentOffset(contentOffset, animated: false)
}
This code avoids the auto sizing UITextView's unnecessary scroll animations and you can expand the size of the text view freely.
Setting textView.scrollable = NO lets me resize the text view without any strange offsets, that's the only way I've been able to figure out. And I guess it's not too much of a limitation for common scenarios, if you want the text view to be scrollable you probably don't need to resize it on the fly since the user can scroll around as the content changes.
I confronted the same issue: changing the UITextView's frame to fit its content had a side effect on the scroll position being wrong. The UITextView scrolled even when the contentSize was fitting the bounds.
I ended up with setting scrollEnabled to true and with rolling the content offset back if the UITextView is not actually scrollable
override var contentOffset: CGPoint {
didSet {
if iOS8 {
// here the contentOffset may become non zero whereas it shouldn't be
if !isContentScrollable && contentOffset.y > 0 {
contentOffset.y = 0
}
}
}
}
var isContentScrollable: Bool {
let result = ceil(contentSize.height) > ceil(height)
return result
}
Actually, I faced the same issue and found that actually this happens only when UITextView has any Autolayout constraints. If you will try to use UITextView without applying any Constraint then this will not happen and will work fine. but, as you apply Auto layout constraints it automatically scrolls to bottom. To deal with this I just add method
-(void)viewDidLayoutSubviews{
[super viewDidLayoutSubviews];
self.textView.contentOffset = CGPointZero;
}
I have one UIImageView (building's floor map) and UIScrollView with gesture recognisers which allow me to scroll horizontally and vertically, zoom in/out. Everything works OK, but the building has two floors, so user should have the option to switch between them. I decided to use segmented control at the top of the map to provide this option.
If I put Segmented Control to the same UIScrollView, it scrolls vertically as well as horizontally. What I am asking is how to fix horizontal position of the Segmented Control, so it will be able to scroll only vertically with map.
I am trying to use this code to test, if it fixes the position of Segmented Control absolutely, but it seems to be that it doesn't.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGRect frame = _floorSelector.frame;
frame.origin.y=50;
frame.origin.x= 160;
_floorSelector.frame = frame;
}
Where is the mistake? Thank you for replies!
I think the issue here is you are misunderstanding how scrolling is implemented in a UIScrollView, and how things are placed in its coordinate space.
When a UIScrollView is scrolled, the frames of its subviews are not changed. Relative to the scrollview, they remain in the same position while the contentOffset and bounds of the scroll view changes. In order to make a subview of a scroll view appear static while the rest of it scrolls, you must change its frame within the scrollview as the bounds change.
With that in mind, what you are doing now is just setting the same frame on that subview repeatedly, which is the same as not doing anything.
It sounds like what you want to do is something like this:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGRect frame = _floorSelector.frame;
frame.origin.x = 160 + scrollView.contentOffset.x;
_floorSelector.frame = frame;
}
Notice I do not change anything in the y axis because based on your question, the vertical scrolling doesn't need to be changed.
I have a UIScrollView that contains multiple UITableViews in it. The design is I have the UIScrollView to be the width of the view which is 320. The tableViews to be offset from the left with 10 pts and a width of 280, in which the next UITableView should be shown (or previewed) with 20 pts being shown.
I want that when I scroll the UIScrollView, it would only move by 290. Is there a method available for this in iOS or I would need a calculation to adjust the contentSize of the UIScrollView
If you enable paging, you will get the effect you are looking for, sans the smaller preview scroll.
One method to overcome this is to make the scrollview's frame smaller (290 points), and have its clipsToBounds property set to NO (so you get the preview of the next portion).
Another is to implement the scrollview's delegate method - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset and calculate where the scrollview should scroll according to velocity. The first method is simpler.
I have a UIView with a CATiledLayer visible within a UIScrollView.
At certain times I need to relocate the window contents relative to the scroll view origin.
I need to change the contentOffset property of the scroll view but, when I redraw, the contents are the same.
The sequence is
scrollView.contentOffset = newoffset ;
[contentView setNeedsDisplay]
This creates a jerky effect as the scrollView shifts.
Is there any way to freeze the visible area of the scroll view until the drawing is complete?
Essentially, I'd like to
[FREEZE DISPLAY]
scrollView.contentOffset = newoffset ; // But have no visible change
[contentView setNeedsDisplay]
[UNFREEZE DISPLAY AFTER a SHORT DELAY]
You should be doing that in your delegate methods of UIScrollView. It has a very specific set of methods that you can use to time your update appropriately.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView;
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;
Between these 3 methods, I'm sure that one of these is going to make that call with the timing that you're looking for.
Last thing, watch out for how many times your calling the setNeedsDisplay method when utilizing these delegates. setNeedsDisplay isn't cheap on memory if you're calling it every millisecond!
Cheers
I have added 10 labels to to display 0 to 9 in UIScrollView, User can see only one label in UIScrollView visible part. User needs to scroll to see other labels. How to determine which label is currently visible in UIScrollView after scroll view decelerating.
Thanks in advance
Use the scroll view's contentOffset and calculate how many "pages" down they have scrolled by dividing the y offset by the content size height.
When scrolling is complete compare contentOffset value with labels positions or view to see which label is currently shown:
Use this method for getting scrolled position:
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
NSLog(#"%f", scrollView.contentOffset.y);
//your logic to check shown label...
int currentVisiblePage = (scrollView.contentOffset.y / self.view.frame.size.height) + 1;
}
if you just want a single scrollable label, would be to use UITextView instead (reference). Disable editing, and you get a scrollable label.
(Taken almost verbatim from: how to add a scroll function to a UILabel)
For more detail:
UILabel inside of UIScrollView – programmatically
Sample code
AutoScrollLabel