Подтвердить что ты не робот

Как сделать круговой UIPickerView (iPhone/iPad)?

Я много разбирался в этом вопросе, но до сих пор неясно, возможно ли это или нет. По существу, я хочу создать UIPickerView, который будет непрерывным в том смысле, что вы можете навсегда его закрутить, и вы никогда не достигнете его конца (поскольку за последним значением следует первое значение).

У меня был обзор в Интернете, и, похоже, для достижения желаемого эффекта существует большое количество хаков. Однако многие из этих решений, похоже, увеличивают количество строк в UIPickerView, чтобы обмануть пользователя, думая, что UIPickerView является непрерывным (однако, в действительности, если они продолжали прокручивать, они в конечном итоге достигли конца).

То, что мне нужно, - это способ создания UIPickerView, который действительно бесконечен в том смысле, что вы никогда не достигнете конца, если вы продолжаете прокручивать дни, недели, месяцы или годы. Я не против слишком много, если решение является взломом, так как я понимаю, что Apple пока не дала способ достичь эффекта.

Пожалуйста, кто-нибудь может посоветовать, как это сделать (или указать мне в правильном направлении, по крайней мере)?

4b9b3361

Ответ 1

Я действительно думаю, что здесь описывается единственный взлом, который вы можете сделать с собственным UIPickerView:

Как вы обмениваете компонент UIPickerView?

Другим способом действительно сделать сборщик в цикле - это реализовать его самостоятельно.

Я видел сборщики, которые были реализованы с cocos2d, то есть OpenGL. Я думаю, вы можете попробовать сделать это, используя UIKit, если вам действительно нужно.

Или просто забудьте об этом и сделайте сборщик с строками NSIntegerMax с повторяемым контентом. Я думаю, что никто не будет вращать его до конца.

Ответ 2

Найти пользовательский класс UIPickerView, который работает очень хорошо и очень прост в реализации здесь

Ответ 3

Это возможно. Вот как вы можете это сделать. Сначала настройте таймер. Предположим, что int maxNumber - это переменная экземпляра, установленная на какое-то произвольное значение.

- ( void) viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
   [self.timer invalidate];
   self.timer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self    selector:@selector(timerFireMethod:) userInfo:nil repeats:YES];

}

- (void) viewWillDisappear:(BOOL)animated{
   [self.timer invalidate];
   [super viewWillDisappear:animated];
}

- (void)viewDidLoad
{
 [super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
 [self.infinitePickerView selectRow:(int)maxNumber*5 inComponent:0 animated:YES];
}

В методе "огонь по таймеру" проверьте, отображается ли какой-либо вид "края" вашего изображения uipickerview.

- (void)timerFireMethod:(NSTimer*)theTimer{
int rowSelected = [self.infinitePickerView selectedRowInComponent:0];    
for (int i=0; i<= 20; i++) {
    UIView * viewBelow = [self.infinitePickerView viewForRow:i forComponent:0];
    UIView * viewAbove = [self.infinitePickerView viewForRow:maxNumber*10-20+i forComponent:0];
    if(viewBelow!=nil || viewAbove!=nil){
        int middlePosition = maxNumber * 5 + (rowSelected % maxNumber);
        [self.infinitePickerView selectRow:middlePosition inComponent:0 animated:NO];
        break;
    }
}
}

Обратите внимание, что это работает, потому что [self.infinitePickerView viewForRow:i forComponent:0]; возвращает UIView только в том случае, если он отображается.

Конечно, ваш UIPickerViewDelegate должен использовать что-то вроде

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
   return  maxNumber * 10; //returning a large number
}

 //You cannot use this method
/*
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row  forComponent:(NSInteger)component{}
 You have to use the method below in lieu of it
*/

 - (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view{

 UILabel * label;

 if (!view) {
    label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0,  self.infinitePickerView.bounds.size.width, 30)];
}else {
    label = (UILabel *) view;     
}
[label setText:[NSString stringWithFormat:@" %d", row % maxNumber]];
return label;
}

Надеюсь, это сработает!!:) Удачи!

Ответ 4

Нет встроенного сборщика, который в любом случае обертывает (а не iOS7.1). Вы можете подделать это следующим образом:

NSArray *picks = @[ @"zero", @"one", @"two", @"three" ]; // 4 entries

// ...

- (NSInteger)pickerView:(UIPickerView *)pickerView 
numberOfRowsInComponent:(NSInteger)component
{
    return (3 * [picks count]); // we're very tricky, displaying only
                                // ...the SECOND set of entries, to
                                // ... give the impression of wrap-around
}

// ...

- (NSString *)pickerView:(UIPickerView *)pickerView 
             titleForRow:(NSInteger)row 
            forComponent:(NSInteger)component
{
    // All "3" sets of entries have the same values;
    // this is what gives the appearance of wrap-around.
    int titleRow = row % [picks count];
    return [picks objectAtIndex: titleRow];
}

// ...

- (void)pickerView:(UIPickerView *)pickerView 
      didSelectRow:(NSInteger)row 
       inComponent:(NSInteger)component
{
    // If the wheel turns to outside our 2nd-set range,
    // ...set it to the matching item in the 2nd set.
    // In this way, we always display what looks like a wrap-around.
    int count = [picks count];
    if ((row <  count)
    ||  (row > (count * 2) )
    {
        [pickerView selectRow: (row % count) inComponent: component animated: NO];
    }
}

Вам, конечно, придется настраивать и настраивать в соответствии с вашими потребностями, но это основной смысл.

Удачи!

Ответ 5

Хм.. Я смотрю вокруг, и есть несколько ссылок на несколько возможностей, наиболее выдающимся из которых является этот: The Abusive Pickerview, основная идея состоит в том, что вы заполняете pickerview тремя наборами ваших данных и запускаете и устанавливаете центр. Всякий раз, когда пользователь прокручивается до центра любого из верхних или нижних наборов, вы устанавливаете значение строки обратно в центр центра! Кажется, что он более подлинный, поэтому делает действительно длинный список, который создаст иллюзию бесконечности. Это решение может быть наиболее эффективным и простым в решении бесконечной задачи pickerview! Надеюсь, это помогло!

Ответ 6

Мне кажется, что решения, требующие большого объема данных, вбиваться в pickerView, являются расточительными. Следующее решение использует smarts вместо памяти.

Единственными строками, которые должны быть заполнены, являются строки, видимые в представлении, и строка, непосредственно предшествующая первой, и строка, следующая за последней. Когда пользователь прокручивает компонент, pickerView: titleForRow: forComponent: вызывается для каждой строки, которая прокручивается.

Итак, решение состоит в том, чтобы обновить данные в pickerView: titleForRow: forComponent: а затем вызвать соответствующий метод для перезагрузки данных, чтобы он был там, когда pickerview прокручивает еще один тик.

Ответ 7

Я знаю, это старый вопрос, но я только что нашел его, когда я его реализую в своем собственном проекте.

Просто используйте метод Morion для большого количества элементов с повторяющимся контентом, затем каждый раз, когда он прекращает прокрутку, reset строка. Единственный способ узнать, что вы обманули, - это если они прокручиваются непрерывно без перерыва, пока он не остановится, никогда не называя функцию didSelectRow. Это займет некоторое посвящение!

Независимо от того, как вы это делаете, мне кажется, что он будет чувствовать себя немного взломанным, и это, должно быть, самый легкий взлом...

Ответ 8

Я сделал циклический tableView на основе UIScrollView. И на основе этого tableView я повторно реализую UIPickerView. Вам может быть интересно это. И это представление выбора имеет всю функцию, которая UIPickerView, но также дает много новых функций, и пользовательский вид этого сборщика намного проще.

https://github.com/danleechina/DLPickerView

И помните, что этот циклический прокрутка DLPickerView действительно циклически прокручивается. Вся магия произошла из-за другого класса DLTableView.

Ответ 9

Я использовал pickerView Selection для создания круговой:

   import UIKit
   class ViewController:        
 UIViewController,UIPickerViewDelegate,UIPickerViewDataSource
{
@IBOutlet weak var picker: UIPickerView!
@IBOutlet weak var myLabel: UILabel!

let numbers = [0,1,2,3,4,5,6,7,8,9]

override func viewDidLoad()
{
    super.viewDidLoad()
    // A.Select Second Row
    picker.selectRow(1, inComponent: 0, animated: false)
}
func numberOfComponents(in pickerView: UIPickerView) -> Int
{
    return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int
{
     //B. Add 2 rows to your array count  
    return numbers.count + 2
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String?
{
    var rowTitle = ""
    switch row
    {
    case 0:
        // C. Set first row title to last component of the array.
         // This row is not visible to the user as it is hidden by the        

         //selection in ViewDidLoad
        rowTitle = "\(numbers.last!)"
    case numbers.count + 1:
        //D. Set last row title to first array component
        rowTitle = "\(numbers.first!)"
    default:
        // E. Remember [row - 1] to avoid errors
        rowTitle = "\(numbers[row - 1])"
    }
    return rowTitle
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int)
{
    var theText = ""
    switch row
    {
    case 0:
      //F. Select Row at array count to load the last row
        pickerView.selectRow(numbers.count , inComponent: 0, animated: false)
        theText = = "\(numbers.last!)"
    case numbers.count + 1:
     //G. This Selection will set the picker to initial state
        pickerView.selectRow(1, inComponent: 0, animated: false)
        theText = "\(numbers.first!)"
    default:
        theText = "\(numbers[row - 1])"
    }
    myLabel.text = theText

}

  }

Ответ 10

Очень простое решение, которое заставит вас подумать, что нет конца представления сборщика, путем масштабирования массива и создания модуля выбрать соответствующий элемент из массива

override func viewDidLoad(){
    super.viewDidLoad()
    self.yourArray.selectRow((yourArray.count*100)/2, inComponent: 0, animated: false)
}

func pickerView(_ pickerView: UIPickerView, numberOfRowaInComponent component: Int) -> Int{
    return yourArray.count*100
}

func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int)->String{
    return yourArray[row % yourArray.count]
}