I'm developing kind of UITextView copy with customizations. For now I need to implement selection cursors (see screenshot of original UITextView below)
As I discovered from Debug View Hierarchy Apple developers draw these dots on separate Window to avoid clipping, and when UIScrollView starts dragging they move these dots inside UITextView, when it stops dragging they move it back to separate window. The only problem with this approach is how can I detect when some of my TextView superview's are UIScrollView and they start/end scrolling? Setting delegate for each of UIScrollView-type superviews looks bad and will bring a lot of headache, cause I will need to manage several delegates if needed (and even detect there change). Any ideas?
/*
In your viewDidLoad or where ever you create the UITextView call this :[self checkParentViewOfTextView:textField];
*/
-(void)checkParentViewOfTextView:(UITextView*)txv {
if ([txv.superview isKindOfClass:[UIScrollView class]]) { // Check if the superview if UIScrollView
UIScrollView *superScroll =(UIScrollView*) txv.superview;
superScroll.delegate = self;// In order to call the delegate methods below
superScroll.tag = 5; // Set a tag to access the current scrollView at these delegate methods
}
}
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
//Any scrollView did begin scrolling
if (scrollView.tag == 5) {
//Actions for your scrollView
}
}
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
//Any scrollView did end scrolling
if (scrollView.tag == 5) {
//Actions for your scrollView
}
}
You can use the same scroll view delegate for all UIScrollViews.
scrollView1.delegate = self
scrollView2.delegate = self
etc...
Just implement the delegate methods and take different action if necessary for each scroll view. Either do this by referencing properties in the class or setting the tag.
func scrollViewDidScroll(scrollView: UIScrollView!) {
if scrollView.tag == 0 {
// Do stuff
} else {
// Do other stuff
}
}
Related
I have a viewController that holds WKWebView in his properties.
I made my viewController to implement UIScrollViewDelegate and in 'didScroll' put some code that wont let the scrollView scroll vertically.
like that:
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
scrollView.contentOffset = CGPointMake(scrollView.contentOffset.x, 0);
}
The disabling part is good I tried it on other scrollView and it works just fine.
I set the webView.scrollView delegate to be the viewController.
I also made a method that loop over all of the subViews of webView and if it comes across another scrollView it set the delegate of that scrollView to be the viewController.
After all that it still not working...
-(void)setDelegateForScrollViewsInView:(UIView *)view{
if (view.subviews.count > 0) {
for (UIView *subView in view.subviews){
if ([subView isKindOfClass:[UIScrollView class]]) {
[((UIScrollView *)subView) setDelegate:self];
[((UIScrollView *)subView) setShowsHorizontalScrollIndicator:false];
[((UIScrollView *)subView) setBackgroundColor:UIColor.blueColor];
}
[self setDelegateForScrollViewsInView:subView];
}
}I }
After View Debugger i found that my webView is build up in that hirarchy:
And my method cant catches the inside scrollView so the disabling of the vertical scroll won't work.
How can I fix it?
I have a scroll view and I want an animation to start when the scrollview is scrolled to its end and a little bit further (+75 px). How is that possible? I thought about an if-condition (if view.bounds.maxy >= 1075). But how can this condition or function be called when the user scrolls?
First, make sure your ViewController is a subclass of UIScrollViewDelegate. Next, you want to set your scrollView's delegate to self in the ViewDidLoad(). Then, you'll want to use scrollViewDidScroll() and handle things from there.
func scrollViewDidScroll(scrollView: UIScrollView) {
if scrollView.contentOffset.y >= 75.0 {
// Your animation code goes HERE... //
}
}
If you want your scroll to go further than the actual visible content, consider adding the required distance (+75px in your case) to the contentSize. This will enable the content to scroll further.
As for the animation, UIScrollViewDelegate has multiple methods that can help you. You can keep a check like:
if scrollView.contentOffset.y >= scrollView.contentSize.height {
// Animation code
}
i'm trying to implement a specific tableview behaviour (Like on Facebook app).
I want to have a dynamic header that will be magnified every time the user scrolls up and will be shrieked when the user scroll down.
In addition i want the tableview to cause the effect of pushing the header and than scrolling the tableview cells.
I used the method:
- (void)scrollViewDidScroll:(UIScrollView *)aScrollView
in this method i calculated the offset and the direction and called a method that shrink or magnify the header accordingly
so far so good.
The thing is that the animation is being performed with the tableview scrolling.
To avoid it, I created a custom scrollview on to of the top of my tableview, I taged the two scrollviews differently.
In the scrollview i created a weak reference of the tableview and a boolean value that indicated if the scrollview should return the tableview touch.
When the shrinking\magnifying animation was finished i changed the boolean value so it will signal the custom scrollview to return the tableview in my HitTest methods that i implemented inside the scrollview.
But hitTest not called when the user keep scrolling (without leafing the finger), in additions now my buttons inside my tableViewCell aren't reacting.
Here is my HitTest Method:
- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
UIView* result = [super hitTest:point withEvent:event];
if (_recieveTouchOnTable)
{
return _table;
}
else
return result;
}
Here is my scrollViewDidScroll method:
(onProgress means that the animation is being performed, so keep returning the custom scrollview)
Tag = 2 = the custom scrollview
Tag = 1 = the tableview
- (void)scrollViewDidScroll:(UIScrollView *)aScrollView {
CGFloat yVelocity = [aScrollView.panGestureRecognizer velocityInView:aScrollView].y;
CGFloat offset = lastCustomScrollViewContentOffset.y-aScrollView.contentOffset.y;
lastCustomScrollViewContentOffset =aScrollView.contentOffset;
if (yVelocity<0)
offset = fabs(offset)*-1;
else if(yVelocity>0)
offset = fabs(offset);
if (offset!=0 && aScrollView.tag == 2)
[self layoutViewAccorrdingToTableviewScorlingVelocity:offset];
if (!onProgress ){
customScrollView.recieveTouchOnTable=YES;
}
}
Am i missing something, or maybe there's a more simple way to do it?
I have created a UITableView that can perform swipe-to-delete on its table cells in normal cases, but when I put the UITableView into a UIScrollView that can be horizontally scrollable, the outer scrollview will swallow the swipe event, thus the swipe-to-delete is not workable.
I'm sorry to tell you that you have to give up one for your function since the two functions rely on the same gesture.
If you want to keep the swipe-delete, set the outer scrollview.scrollEnabled = NO. I think that would help.
If not, have a button to start the tableview edit mode. That will make you delete cell with the scrollview can be slided.
I've finally found solution!
Subclass the outer UIScrollView, and override a method
-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
#interface AllowSwipeScrollView : UIScrollView
#end
#implementation AllowSwipeScrollView
-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
BOOL inTableViewCell = .... // check the current touch is in table view cell
if (inTableViewCell) {
return NO;
}else{
return [super gestureRecognizerShouldBegin:gestureRecognizer];
}
}
#end
And make sure the UITableView instances are in AllowSwipeScrollView.
try This condition
if (ScrollView == self.tableView) return;
in scrollviewdidscroll method.
I have a custom uiscrollview inside each table cell. It works great except one condition. When you scroll the scrollview and it do autoscroll/decelerate. At same time if you scroll table view quickly up and down it also moves the scrollview in the table cell which will result in scrollViewDidScroll getting called for scrollview and messed up with my logic.
You need to check which UIScrollView is actually scrolling:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if (scrollView == yourScrollView)
{
// Do something
}
else
{
// Do something amazing
}
}