私はこの質問をよく調べましたが、それが可能かどうかはまだわかりません。基本的に私がやりたいのは、永久に回転でき、最後に到達することは決してないという意味で連続的なUIPickerView
を作成することです(最後の値の後に最初の値が続くため)。
私はオンラインで周りを見回しましたが、望ましい効果を達成するためのさまざまなハックがあるようです。ただし、これらのソリューションの多くは、UIPickerView
の行数を増やして、ユーザーをだましてUIPickerView
が連続していると思わせるように見えます(ただし、実際には、スクロールし続けると、最終的には終わり)。
私が求めているのは、数日、数週間、数か月、または数年スクロールし続けると終わりに到達しないという意味で、真に無限のUIPickerViewを作成する方法です。 Appleはまだ効果を達成する方法を提供していないことを理解しているので、解決策がハックであるかどうかはあまり気にしません。
誰かがこれを行う方法についてアドバイスできますか(または少なくとも私を正しい方向に向けてください)?
ネイティブUIPickerViewで実行できる唯一のハックはここで説明されていると私は本当に思います:
IPickerViewコンポーネントをどのようにラップアラウンドさせますか?
本当にループしたピッカーを作成するもう1つの方法は、自分で実装することです。
OpenGLベースのcocos2dで実装されたピッカーを見ました。本当に必要な場合は、UIKitを使用してそれを試すことができると思います。
または、それを忘れて、繰り返し可能なコンテンツを含むNSIntegerMax行でピッカーを作成します。最後まで誰も回さないと思います。
非常にうまく機能し、実装が非常に簡単なカスタムUIPickerView
クラスを見つけます ここ
それが可能だ。これがあなたがそれをする方法です。まずタイマーを設定します。 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];
}
Timer fireメソッドで、uipickerviewの「Edge」ビューのいずれかが表示されているかどうかを確認します。
- (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;
}
これがうまくいくことを願っています!! :) 幸運を!
ラップするネイティブピッカーはありません(とにかく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];
}
}
もちろん、ニーズに合わせて微調整して調整する必要がありますが、これが基本的な要点です。
幸運を!
うーん..私は周りを見回してきましたが、いくつかの可能性へのリンクがいくつかありますが、最も優れているのはこれです: 虐待的なピッカービュー 、基本的な考え方は、ピッカービューに3を入力することですデータとスタートのセットとセンターセット。ユーザーが上部または下部のセットのいずれかの中央にスクロールするたびに、行の値を中央のセットの中央に戻します。無限の幻想を生み出す本当に長いリストを作るよりも本物のようです。このソリューションは、無限ピッカービューの問題を解決する上で最も効果的で簡単な場合があります。これがお役に立てば幸いです。
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
}
}
UIScrollView
に基づいて循環tableViewを作成しました。そして、このtableViewに基づいて、UIPickerView
を再実装します。あなたはこれに興味があるかもしれません。そして、このピッカービューには、UIPickerView
のすべての機能がありますが、多くの新機能もあり、このピッカービューのカスタムははるかに簡単です。
https://github.com/danleechina/DLPickerView
また、このDLPickerViewの周期的なスクロールは、実際には周期的にスクロールしていることに注意してください。すべての魔法は別のクラスDLTableView
のために起こりました。
配列をスケールアップし、モジュラスに配列から対応するアイテムを選択させることにより、ピッカービューの終わりがないとuに思わせる非常に単純なソリューション
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]
}
古い質問だとは思いますが、自分のプロジェクトで実装しているときに見つけました。
繰り返しコンテンツを含む多数のアイテムに対してMorionの方法を使用するだけで、スクロールが停止するたびに行をリセットします。だれかがあなたがだまされたことを理解する唯一の方法は、didSelectRow関数を呼び出さずに、停止するまで途切れることなく継続的にスクロールすることです。少しの献身が必要です!
あなたがそれをどのように行うかに関係なく、それは少しハッキーに感じるだろうと私には思えます、そしてこれは最も簡単なハックでなければなりません...
大量のデータをpickerViewに詰め込む必要があるソリューションは無駄だと私には思えます。次のソリューションは、メモリの代わりにスマートを使用します。
入力する必要がある行は、ビューに表示されている行と、最初の行の直前の行と最後の行の直後の行だけです。ユーザーがコンポーネントをスクロールすると、スクロールする行ごとにpickerView:titleForRow:forComponent:が呼び出されます。
したがって、解決策は、pickerView:titleForRow:forComponent:のデータを更新してから、適切なメソッドを呼び出してデータを再読み込みし、pickerviewがもう1ティックスクロールしたときにデータがそこにあるようにすることです。