UITableView: scrolling programmatically the conten

2019-02-21 05:02发布

问题:

Hi i'm trying to forward the touches I receive from an UIView which is in front of an UITableView. But doins so I can't make the table scroll anymore (see here).

So now I'm trying to make tha tableview scroll programmatically and I am looking at setContentOffset:animated: and scrollRectToVisible:animated: with having success only with the first.
Here is my code in a class that subclasses the UITableView:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    NSLog(@"BEGTB");
    //previousXPan = 0.0;

    UITouch * touch = [touches anyObject];
    CGPoint tPoint = [touch locationInView:self]; 
    previousYPan = tPoint.y;

    [super touchesBegan:touches withEvent:event];
    //
    //[super touchesShouldBegin:touches withEvent:event inContentView:self];
    //[[self nextResponder] touchesBegan:touches withEvent:event];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
    UITouch * touch = [touches anyObject];
    CGPoint tPoint = [touch locationInView:self]; 


    NSLog(@"MOVTB");
    NSLog(@"BOUNDZ %f, %f, %f, %f", self.bounds.origin.x, self.bounds.origin.y, self.bounds.size.height, self.bounds.size.width);
    NSLog(@"CONTENT SIZE  %f, %f",  self.contentSize.height, self.contentSize.width);

    CGRect rc = [self bounds];
    NSLog(@"%f %f", rc.size.height, rc.size.width);
    CGRect newRect = CGRectMake(rc.origin.x, rc.origin.y + self.contentSize.height, self.contentSize.width, fabs(tPoint.y - previousYPan));
    NSLog(@"BOND RECT %f, %f, %f, %f", rc.origin.x, rc.origin.y, rc.size.height, rc.size.width);
    NSLog(@"NEW RECT %f, %f, %f, %f", newRect.origin.x, newRect.origin.y, newRect.size.height, newRect.size.width);
    //[self scrollRectToVisible:newRect animated:YES];
    NSLog(@"Content OFFSET %f",tPoint.y - previousYPan);
    [self setContentOffset:CGPointMake(rc.origin.x,(tPoint.y - previousYPan) *2.0 )animated:YES];
    previousYPan = tPoint.y;
    //[super touchesMoved:touches withEvent:event];
    //[[self nextResponder] touchesMoved:touches withEvent:event];
}

But the result is really laggy and buggy. Any better idea?

回答1:

I almost found a suitable solution (it is not like a normal scrolling but...).

First I determine the mamimum and minimum amount of pixels in the content area of the table view on the Y axis ( the height of the contentSize when the view has been fully loaded).

The I check the movement done incrementally but not referencing the position of the touch in the table view! I have to check it on a top layered UIView that covers it, because when you alter the content offset of the table you change dynamically its dimensions and you can end you having an acceleration effect .

Here is some code:

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
    UITouch * touch = [touches anyObject];

    CGPoint tPoint = [touch locationInView:[viewController draggableAreaView]];



    CGRect rc = [self bounds];


    float totalOS = tPoint.y - previousYPan;
    if ((contentOffSetY >= minY && contentOffSetY <= maxY) ||
        (contentOffSetY < minY - 5 && totalOS < 0) ||
        (contentOffSetY > maxY + 5 && totalOS > 0))
    {

        if (totalOS > 0)
            totalOS += OFFSET;
        else if (totalOS < 0)
            totalOS -= OFFSET;
        [self setContentOffset:CGPointMake(rc.origin.x,self.contentOffset.y + totalOS)animated:NO];

    }
    else /*if (contentOffSetY < minY - 5 && totalOS < 0) */
    {
        [self resetOffset];
    }
    previousYPan = tPoint.y; 

}

- (void)resetOffset{

    CGRect rc = [self bounds];
    if(contentOffSetY < minY)
    {
        [self setContentOffset:CGPointMake(rc.origin.x, minY + 50)animated:YES];
    }
    else if (contentOffSetY > maxY)
    {
        [self setContentOffset:CGPointMake(rc.origin.x, maxY - 50)animated:YES];
    }
}

Some more tips:

  • here draggableAreaView is the top UIView from which I get an "absolute" position
  • OFFSET is a constant defined to increment linearly the speed of the scroolling (without it the touchesMoved: , called many times, gives a relative movement of just one pixel each time)
  • ,minY and maxY are the precalculated limit values (in order to compute them I calculated the height of all the cells in the table for max and the height of the visible content view for min)
  • I added some displacement to minY and maxY in order to have a more visible animation