2015-09-11 6 views
9

मैंने अपने UITableViews में सेल्स को पुन: व्यवस्थित करने के लिए एक सिस्टम लागू किया है। सब कुछ ठीक है सिवाय इसके कि मैं कोशिकाओं को उस स्थिति में पुन: व्यवस्थित नहीं कर सकता जो आईफोन स्क्रीन में नहीं दिखाया जा रहा है।आईओएस ऐप में UITableViewCells खींचते समय आसानी से UITableView

तो मैं जांच करने के लिए एक शर्त लागू कर दिया है कि अगर मैं स्क्रॉल करने के लिए

NSArray *indexVisibles = [_tableView indexPathsForVisibleRows]; 
NSInteger indexForObject = [indexVisibles indexOfObject:indexPath]; 
if (indexForObject == NSNotFound){ 
    [_tableView scrollToRowAtIndexPath:indexPath 
              atScrollPosition:UITableViewScrollPositionTop 
                animated:YES]; 
} 

मेरे समस्या यह है कि एनीमेशन मिठाई और साफ नहीं है है।

enter image description here

मुझे लगता है कि पता चल सके कि एक सेल से पता चला है के संचालन अपने सिस्टम के लिए बहुत बड़ा है और जब मैं कोशिकाओं को स्थानांतरित एक छोटी सी देरी करते हैं, लेकिन यह भी, मुझे यकीन है कि क्यों स्क्रॉल तो है नहीं कर रहा हूँ जब सेल छुपा रहता है तो मुश्किल होती है।

मैंने UITableViewScrollPositionTop को UITableViewScrollPositionMiddle में बदल दिया है और अब यह बेहतर है लेकिन वेग बहुत बड़ा है इसलिए हमेशा मेरे UITableView के शीर्ष पर स्क्रॉल होता है।

मैं इसे धीरे-धीरे करना चाहता हूं।

अन्य विफलता की कोशिश करता:

विकल्प 1:

[UIView animateWithDuration:0.2 
              animations:^{_tableView.contentOffset = CGPointMake(0.0, _tableView.contentOffset.y - 50);} 
              completion:^(BOOL finished){ }]; 

लेकिन यह दोनों समस्याओं मिल गया है:

  1. आंदोलन अभी भी भारी है
  2. जब पहला तत्व करने के लिए ड्रैग , यह तत्व मध्य छिपा है

enter image description here

विकल्प 2:

[UIView animateWithDuration: 1.0 
              animations: ^{ 
               [_tableView scrollToRowAtIndexPath:indexPath 
                    atScrollPosition:UITableViewScrollPositionMiddle 
                      animated:NO]; 
              }completion: ^(BOOL finished){ 

              } 
          ]; 
+1

कृपया इस भंडार की आशा करें कि यह आपके लिए काम है। https://github.com/hpique/HPReorderTableView –

+0

यह सही लगता है लेकिन इसमें कुछ कीड़े हैं और यह मेरे प्रोजेक्ट पर लागू नहीं है। लेकिन मैं त्रुटि खोजने के लिए अपने कोड का अध्ययन कर रहा हूं और उन्हें – EnriMR

उत्तर

11

मैंने अपनी समस्या को एक बहुत ही सुन्दर समाधान के साथ हल किया है, इसलिए मैं इसे तीन सरल चरणों में कैसे समझाऊंगा।

मैं https://github.com/hpique/HPReorderTableView से कुछ प्रेरणा का उपयोग करें और अपने खुद के भंडार में इसे साझा https://github.com/enrimr/EMRReorderTableCells

ए gestureRecognition

प्रबंधित है longPressGestureRecognized:

- (IBAction)longPressGestureRecognized:(id)sender { 

    _reorderGestureRecognizer = (UILongPressGestureRecognizer *)sender; 

    CGPoint location = [_reorderGestureRecognizer locationInView:_tableView]; 
    NSIndexPath *indexPath = [self getCellIndexPathWithPoint:location]; 

    UIGestureRecognizerState state = _reorderGestureRecognizer.state; 
    switch (state) { 
     case UIGestureRecognizerStateBegan: { 

      NSIndexPath *indexPath = [_tableView indexPathForRowAtPoint:location]; 
      if (indexPath == nil) 
      { 
       [self gestureRecognizerCancel:_reorderGestureRecognizer]; 
       break; 
      } 

      // For scrolling while dragging 
      _scrollDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(scrollTableWithCell:)]; 
      [_scrollDisplayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; 

      // Check for the right indexes (between margins of offset 
      if (indexPath.row >=_elementsOffset && indexPath.row < [_elements count]+_elementsOffset){ 

       if (indexPath) { 
        sourceIndexPath = indexPath; 

        id sourceElement = [_elements objectAtIndex:sourceIndexPath.row-_elementsOffset]; 

        snapshot = [self createSnapshotForCellAtIndexPath:indexPath withPosition:location]; 
       } 
      } else { 
       sourceIndexPath = nil; 
       snapshot = nil; 
      } 
      break; 
     } 

     case UIGestureRecognizerStateChanged: { 

      [self calculateScroll:_reorderGestureRecognizer]; 

      if (sourceIndexPath != nil && indexPath.row >=_elementsOffset && indexPath.row < [_elements count]+_elementsOffset){ 
       [self updateSnapshotWithPosition:location]; 

       // Is destination valid and is it different from source? 
       if (indexPath && ![indexPath isEqual:sourceIndexPath]) { 
        if (indexPath.row - sourceIndexPath.row <= 1){ 

         id sourceElement = [_elements objectAtIndex:sourceIndexPath.row-_elementsOffset]; 
         id targetElement = [_elements objectAtIndex:indexPath.row-_elementsOffset]; 

         sourceIndexPath = [self exchangeElement:sourceElement byElement:targetElement]; 
        } 

       } 
      } 
      break; 
     } 

     case UIGestureRecognizerStateEnded: 
     { 
      // For scrolling while dragging 
      [_scrollDisplayLink invalidate]; 
      _scrollDisplayLink = nil; 
      _scrollRate = 0; 


      // Check if it is the last element 
      if (sourceIndexPath != nil){ 
       id element; 
       if (indexPath.row <=_elementsOffset){ 
        element = [_elements firstObject]; 
       } else if (indexPath.row > [_elements count]-1+_elementsOffset){ 
        element = [_elements lastObject]; 
       } else { 
        element = [_elements objectAtIndex:indexPath.row-_elementsOffset]; 
       } 
      } 

     } 

     default: { 
      // Clean up. 
      [self deleteSnapshotForRowAtIndexPath:sourceIndexPath]; 

      [appDelegate startTimer]; 

      break; 
     } 
    } 
} 

इशारा रिकॉग्नाइज़र कैंसल:

यह पुनरावृत्ति कार्रवाई को समाप्त करने के लिए इशारा पहचान को रद्द करने के लिए उपयोग किया जाता है।

-(void) gestureRecognizerCancel:(UIGestureRecognizer *) gestureRecognizer 
{ // See: http://stackoverflow.com/a/4167471/143378 
    gestureRecognizer.enabled = NO; 
    gestureRecognizer.enabled = YES; 
} 

scrollTableWithCell:

विधि यह है जब आप (ऊपर और नीचे) मेज की सीमा में हैं स्क्रॉल आंदोलन बनाने के लिए कहा जाता है

- (void)scrollTableWithCell:(NSTimer *)timer 
{ 
    UILongPressGestureRecognizer *gesture = _reorderGestureRecognizer; 
    const CGPoint location = [gesture locationInView:_tableView]; 

    CGPoint currentOffset = _tableView.contentOffset; 
    CGPoint newOffset = CGPointMake(currentOffset.x, currentOffset.y + _scrollRate * 10); 

    if (newOffset.y < -_tableView.contentInset.top) 
    { 
     newOffset.y = -_tableView.contentInset.top; 
    } 
    else if (_tableView.contentSize.height + _tableView.contentInset.bottom < _tableView.frame.size.height) 
    { 
     newOffset = currentOffset; 
    } 
    else if (newOffset.y > (_tableView.contentSize.height + _tableView.contentInset.bottom) - _tableView.frame.size.height) 
    { 
     newOffset.y = (_tableView.contentSize.height + _tableView.contentInset.bottom) - _tableView.frame.size.height; 
    } 

    [_tableView setContentOffset:newOffset]; 

    if (location.y >= 0 && location.y <= _tableView.contentSize.height + 50) 
    { 

     [self updateSnapshotWithPosition:location]; 
     NSIndexPath *indexPath = [self getCellIndexPathWithPoint:location]; 

     // CHeck if element is between offset limits. 
     if (![indexPath isEqual:sourceIndexPath] && 
      indexPath.row >= _elementsOffset && 
      indexPath.row - _elementsOffset < [_elements count] && 
      sourceIndexPath.row >= _elementsOffset && 
      sourceIndexPath.row - _elementsOffset < [_elements count]) 
     { 
      id sourceElement = [_elements objectAtIndex:sourceIndexPath.row-_elementsOffset]; 
      id targetElement = [_elements objectAtIndex:indexPath.row-_elementsOffset]; 
      [self exchangeElement:sourceElement byElement:targetElement]; 
      sourceIndexPath = indexPath; 
     } 
    } 
} 

बी स्नैपशॉट प्रबंधन

createSnapshotForCellAtIndexPath:

रिटर्न एक के एक अनुकूलित स्नैपशॉट: withPosition

विधि है कि एक स्नैपशॉट सेल की (एक छवि प्रतिलिपि) आप आगे बढ़ रहे हैं बनाता है

-(UIView *)createSnapshotForCellAtIndexPath:(NSIndexPath *)indexPath withPosition:(CGPoint)location{ 
    UITableViewCell *cell = [_tableView cellForRowAtIndexPath:indexPath]; 

    // Take a snapshot of the selected row using helper method. 
    snapshot = [self customSnapshoFromView:cell]; 

    // Add the snapshot as subview, centered at cell's center... 
    __block CGPoint center = cell.center; 
    snapshot.center = center; 
    snapshot.alpha = 0.0; 

    [_tableView addSubview:snapshot]; 
    [UIView animateWithDuration:0.25 animations:^{ 

     // Offset for gesture location. 
     center.y = location.y; 
     snapshot.center = center; 
     snapshot.transform = CGAffineTransformMakeScale(1.05, 1.05); 
     snapshot.alpha = 0.98; 
     cell.alpha = 0.0; 

    } completion:^(BOOL finished) { 

     cell.hidden = YES; 
    }]; 

    return snapshot; 
} 

customSnapshoFromView दिया गया दृश्य */

- (UIView *)customSnapshoFromView:(UIView *)inputView { 

    // Make an image from the input view. 
    UIGraphicsBeginImageContextWithOptions(inputView.bounds.size, NO, 0); 
    [inputView.layer renderInContext:UIGraphicsGetCurrentContext()]; 
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 

    // Create an image view. 
    snapshot = [[UIImageView alloc] initWithImage:image]; 
    snapshot.layer.masksToBounds = NO; 
    snapshot.layer.cornerRadius = 0.0; 
    snapshot.layer.shadowOffset = CGSizeMake(-5.0, 0.0); 
    snapshot.layer.shadowRadius = 5.0; 
    snapshot.layer.shadowOpacity = 0.4; 

    return snapshot; 
} 

updateSnapshotWithPosition:

को देखते हुए एक CGPoint, यह सेल आप _tableView

-(void)updateSnapshotWithPosition:(CGPoint)location{ 
    CGPoint center = snapshot.center; 
    center.y = location.y; 
    snapshot.center = center; 
} 

की सही जगह में आगे बढ़ रहे हैं दिखाने के लिए स्नैपशॉट स्थिति में परिवर्तन हटाएं स्नैपशॉटफॉररोएट इंडेक्सपैथ:

जब खत्म खींचते समय, आप _tableView

-(void)deleteSnapshotForRowAtIndexPath:(NSIndexPath *)sourceIndexPath{ 
    UITableViewCell *cell = [_tableView cellForRowAtIndexPath:sourceIndexPath]; 
    cell.hidden = NO; 
    cell.alpha = 0.0; 

    [UIView animateWithDuration:0.25 animations:^{ 

     snapshot.center = cell.center; 
     snapshot.transform = CGAffineTransformIdentity; 
     snapshot.alpha = 0.0; 
     cell.alpha = 1.0; 

    } completion:^(BOOL finished) { 
     [snapshot removeFromSuperview]; 
    }]; 
} 

calculateScroll

-(void)calculateScroll:(UIGestureRecognizer *)gestureRecognizer{ 

    const CGPoint location = [gestureRecognizer locationInView:_tableView]; 

    CGRect rect = _tableView.bounds; 
    // adjust rect for content inset as we will use it below for calculating scroll zones 
    rect.size.height -= _tableView.contentInset.top; 

    //[self updateCurrentLocation:gestureRecognizer]; 

    // tell us if we should scroll and which direction 
    CGFloat scrollZoneHeight = rect.size.height/6; 
    CGFloat bottomScrollBeginning = _tableView.contentOffset.y + _tableView.contentInset.top + rect.size.height - scrollZoneHeight; 
    CGFloat topScrollBeginning = _tableView.contentOffset.y + _tableView.contentInset.top + scrollZoneHeight; 

    // we're in the bottom zone 
    if (location.y >= bottomScrollBeginning) 
    { 
     _scrollRate = (location.y - bottomScrollBeginning)/scrollZoneHeight; 
    } 
    // we're in the top zone 
    else if (location.y <= topScrollBeginning) 
    { 
     _scrollRate = (location.y - topScrollBeginning)/scrollZoneHeight; 
    } 
    else 
    { 
     _scrollRate = 0; 
    } 

} 

सी से स्नैपशॉट हटाने की आवश्यकताइसका उपयोग कैसे करें

अपनी init विधि में, तालिका दृश्य में एक इशारा पहचानकर्ता असाइन करें। कार्रवाई के रूप में निरुपित विधि longPressGestureRecognized: इस प्रकार है:

_reorderGestureRecognizer = [[UILongPressGestureRecognizer alloc] 
               initWithTarget:self action:@selector(longPressGestureRecognized:)]; 

    [_tableView addGestureRecognizer:_reorderGestureRecognizer]; 

चर आप ऊपर कोड का उपयोग करने की आवश्यकता होगी घोषित समझाया

@implementation YourClassName{ 

    CADisplayLink *_scrollDisplayLink; 
    CGFloat _scrollRate; 
    UIView *snapshot; // A snapshot of the row user is moving. 
    NSIndexPath *sourceIndexPath; // Initial index path, where gesture begins. 
} 

और वह सब कुछ आप समस्या मैं था हल करने के लिए की आवश्यकता होगी है।

+0

क्या आप अपने व्यू कंट्रोलर के सभी स्रोत कोड साझा कर सकते हैं या आप दिखा सकते हैं कि '_elementsOffset' (इसकी गणना कैसे की जाती है) और अन्य सहायक विधियां उदा। 'गणना करें स्क्रॉल' – Karaban

+0

तत्व ऑफसेट वैकल्पिक है, यदि आप अपनी तालिका के शीर्ष में तत्वों को लॉक करना चाहते हैं तो आप इसका उपयोग कर सकते हैं। मेरे पास इस श्रेणी में मेरी कक्षा https://github.com/enrimr/EMRReorderTableCells में साझा है यदि आपके कोई प्रश्न हैं, तो मुझसे पूछने में संकोच न करें;) उम्मीद है कि यह आपकी मदद कर सकता है! – EnriMR

+0

बहुत बहुत धन्यवाद !!! – Karaban

1

मैं भी एक तरह से लंबे समय तक उन्हें दबाकर tableview कोशिकाओं रेंडर करने के लिए के लिए देख रहा था। और मुझे उस उद्देश्य के लिए एक भंडार मिला। यदि आपको अपनी परियोजना में तृतीय पक्ष लाइब्रेरी डालने पर कोई फर्क नहीं पड़ता है तो इसे जांचें! :)

LPRTableView

व्यक्तिगत तौर पर मैं के लिए मेरे एप्लिकेशन चीता नोट इस कोड का उपयोग। और वे एक आकर्षण की तरह काम कर रहे हैं! अत्यधिक सिफारिशित!

+1

ठीक कर रहा हूं मैं उद्देश्य-सी के साथ काम कर रहा हूं लेकिन उस संग्रह के विवरण में, मैंने पाया है कि https://github.com/bvogelzang/BVReorderTableView I'm परीक्षण करने जा रहे हैं – EnriMR

+0

हाँ! सौभाग्य! :) –

+1

मैं उस प्रोजेक्ट को संकलित नहीं कर सकता – EnriMR

0

विकल्प एक कोशिश का उपयोग करना घसीटा सेल स्थिति के लिए स्क्रॉल करने के लिए - 1 जब घसीटा सेल शीर्ष पर है:

[UIView animateWithDuration: 1.0 animations: ^{ 
    [_tableView scrollToRowAtIndexPath:indexPathForCellBefore atScrollPosition:UITableViewScrollPositionTop animated:NO]; 
} completion: ^(BOOL finished){ 
}]; 

:

NSArray *indexVisibles = [_tableView indexPathsForVisibleRows]; 
NSInteger indexForObject = [indexVisibles indexOfObject:indexPath]; 
if (indexForObject == 0){ 
    [_tableView scrollToRowAtIndexPath:indexPathForCellBefore 
              atScrollPosition:UITableViewScrollPositionTop 
                animated:YES]; 
} 

सुचारू रूप से tableview निम्नलिखित स्निपेट का उपयोग स्क्रॉल करने के लिए निस्संदेह आपको स्क्रॉल करते समय काम करने के लिए संशोधित करने की आवश्यकता होती है।

+0

यह मेरी मदद नहीं करता है क्योंकि 'scrollToRowAtIndexPath: atScrollPosition: एनिमेटेड' के लिए एनीमेशन बहुत मजबूत है, मैं UITableView को आसानी से स्क्रॉल करना चाहता हूं – EnriMR

+0

ठीक है लेकिन क्या आपने इसे आजमाया है? – hasan83

+1

हां, यह मेरी समस्याओं में से एक हल करता है कि जब आप इसे शीर्ष पर खींचते हैं तो उस स्थिति को खींचने वाले सेल को बनाए रखने के तरीके के बारे में बताया जाता है, लेकिन आंदोलन – EnriMR

संबंधित मुद्दे