2010-05-11 38 views
7

Tôi đang triển khai UISlider mà người dùng có thể thao tác để đặt khoảng cách. Tôi chưa bao giờ sử dụng CocoaTouch UISlider, nhưng đã sử dụng các thanh trượt khung khác, thường có một biến để đặt thuộc tính "bước" và "trợ giúp" khác.Làm thế nào để làm cho đầu ra UISlider đẹp tròn số theo cấp số nhân?

Tài liệu cho UISlider chỉ giao dịch với giá trị cực đại và cực đại, và đầu ra luôn luôn là 6 phẩy thập phân với mối quan hệ tuyến tính với vị trí của "thanh trượt nob". Tôi đoán tôi sẽ phải thực hiện từng bước chức năng mong muốn.

Đối với người dùng, giá trị tối thiểu/tối đa từ 10 m đến 999 Km, tôi đang cố gắng triển khai điều này theo cách theo cấp số nhân, điều đó sẽ cảm thấy tự nhiên đối với người dùng. I E. người dùng trải nghiệm cảm giác kiểm soát các giá trị, lớn hay nhỏ. Ngoài ra, "đầu ra" có giá trị hợp lý. Giá trị như 10m 200m 2.5km 150 km, vv thay vì 1.2342356 m hoặc 108.93837756 km.

Tôi muốn kích thước bước tăng 10m trong 200m đầu tiên, sau đó có thể lên tới 50m đến 500m, sau đó khi vượt qua giá trị 1000 m, nó bắt đầu đối phó với Kilômét, do đó, đó là bước kích thước = 1 km cho đến 50 km, sau đó có thể 25 km bước vv

Bất kỳ cách nào tôi đi về điều này tôi sẽ làm rất nhiều làm tròn và rất nhiều tính toán được bọc trong một forrest của báo cáo if và NSString/Số chuyển đổi , mỗi lần người dùng di chuyển thanh trượt chỉ một chút.

Tôi đã hy vọng một người nào đó có thể cho tôi mượn một chút cảm hứng/giúp toán hoặc làm cho tôi nhận thức được cách tiếp cận gọn gàng hơn để giải quyết vấn đề này.

Ý tưởng cuối cùng của tôi là điền và mảng với một giá trị chuỗi 100, sau đó có giá trị int thanh trượt tương ứng với một chuỗi, điều này không phải là rất linh hoạt, nhưng có thể thực hiện được.

Cảm ơn bạn đã hỗ trợ trước :)

+1

để bây giờ tôi sử dụng Số táo để tạo số thực mà tôi muốn (bằng cách nhập một vài số, hãy chọn và kéo. Điều này làm cho số tạo ra các số trong cùng một khoảng thời gian) Tôi đã làm khoảng 75 con số. Sau đó, tôi xuất dưới dạng CSV, chạy nó qua Textmate và thực hiện một số regexp để lấy các số như chuỗi @ "number", Dán số vào một mảng và có thanh trượt kéo chúng ra: \t NSInteger numberLookup = lroundf ([slider giá trị]); \t NSString * distanceString = [sliderNumbers objectAtIndex: numberLookup]; Tôi đặt thanh trượt tối thiểu là 0 và tối đa là [số trượt trượt]. Tôi vẫn muốn nghe về ý tưởng :) – RickiG

Trả lời

0

Câu trả lời dễ nhất là sử dụng Kiểm soát phân đoạn với các kích thước bước khác nhau. Tùy thuộc vào tùy chọn người dùng chọn, kích thước thanh trượt của bạn sẽ là bao nhiêu. Tôi thậm chí còn khuyên rằng đây có lẽ là một cách thân thiện với người dùng hơn để tiếp cận nó :).

Hãy sử dụng Dapp để chơi với giao diện ứng dụng của bạn và xem cách kiểm soát phân đoạn có thể phù hợp với thiết kế.

Tuy nhiên ... bạn muốn có cách tiếp cận gọn gàng hơn);

Tôi bắt đầu viết 10 hoặc nhiều bước cần thiết, nhưng tôi dừng lại khi tôi nhận ra bạn có thể đã đến một giải pháp tương tự. Ý tưởng mảng chuỗi của bạn là tốt, tôi giả sử bạn sẽ chỉ cần chuyển đổi giá trị thanh trượt thành một số nguyên và lấy chỉ mục có liên quan từ mảng?

Đôi khi các lập trình viên chúng ta đi quá xa với cách tiếp cận của chúng tôi cho một vấn đề. Có, một mảng chuỗi không phải là giải pháp 'linh hoạt' nhất nhưng nó nhanh! Và, tôi cho rằng ngay cả một giải pháp toán học thiên tài cũng không linh hoạt như bạn nghĩ. Ngoài ra, nếu bạn không có kế hoạch thay đổi các giá trị bất cứ lúc nào sớm và không cần các phạm vi thanh trượt khác nhau trên các thanh trượt khác nhau, thì việc tạo một mảng tĩnh là có ý nghĩa.

Chúc may mắn!:)

+0

Hi Raal và cảm ơn. "Đôi khi lập trình viên chúng tôi đi quá xa với cách tiếp cận của chúng tôi cho một vấn đề" hoàn toàn kết thúc trong vài giờ gần đây :) Tôi mất 25 phút để đặt cùng một giải pháp mà tôi đã mô tả trong bình luận trước đó của tôi với mảng. Nó hoạt động hoàn hảo, tôi chỉ đối phó với 75 giá trị nên thời gian tra cứu/chi phí gần như không tồn tại. Tôi đã làm cho thanh trượt của tôi đi từ 0-74 và tôi làm tròn/đúc các số thành int và chỉ tìm kiếm giá trị tương ứng. Tôi đã chọn một giá trị của chỉ mục 21 cho khi nó thay đổi từ mét đến km. Tôi sẽ chỉ đăng mã trong câu trả lời nếu có ai có thể hưởng lợi từ nó. – RickiG

5

Một giải pháp mở rộng quy mô nhanh chóng bao gồm ba phương pháp đặc biệt:

- (CGFloat)scaleValue:(CGFloat)value { 
    return pow(value, 10); 
} 

- (CGFloat)unscaleValue:(CGFloat)value { 
    return pow(value, 1.0/10.0); 
} 

- (CGFloat)roundValue:(CGFloat)value { 
    if(value <= 200) return floor(value/ 10) * 10; 
    if(value <= 500) return floor(value/ 50) * 50; 
    if(value <= 1000) return floor(value/100) * 100; 
    if(value <= 50000) return floor(value/1000) * 1000; 
    return floor(value/25000) * 25000; 
} 

Phản ứng lại với những thay đổi thanh trượt sẽ là một cái gì đó như:

- (void)sliderChange:(id)sender { 
    CGFloat value = mySlider.value; 
    value = [self scaleValue:value]; 
    value = [self roundValue:value]; 
    valueLabel.text = [NSString stringWithFormat:@"%f", value]; 
} 

Bạn có thể init với đoạn mã sau:

mySlider.maximumValue = [self unscaleValue:999000]; 
mySlider.minimumValue = [self unscaleValue:10]; 

Tôi có tất cả những điều trên để làm việc mà không gặp bất kỳ sự cố nào nhưng có thể sử dụng một số chống đạn. Các phương pháp scaleValue:unscaleValue: nên kiểm tra các giá trị không được hỗ trợ và tôi chắc chắn phương pháp sliderChange: có thể hiệu quả hơn.

Xét về tốc độ, tôi chắc chắn rằng điều này nhanh hơn việc kéo các đối tượng ra khỏi một mảng. Các hành vi trượt thực tế có thể cảm thấy một chút sôi nổi và không có nhiều kiểm soát chính xác những gì các giá trị có sẵn với thanh trượt, vì vậy nó có thể không làm chính xác những gì bạn muốn. Sử dụng sức mạnh thực sự cao dường như làm cho nó hữu ích hơn.

+0

Cảm ơn bạn MrHen! Đó là một cách tiếp cận khá nạc cho các giá trị thực sự theo cấp số nhân. Khi tôi tối ưu hóa, tôi sẽ thử cách so sánh lại lần tra cứu mảng. Cảm ơn bạn lần nữa. – RickiG

0
+ (NSArray*) getSliderNumbers { 

    NSArray *sliderNumbers = [NSArray arrayWithObjects:@"10", 
          @"20", 
          @"30", 
          @"40", 
          @"50", 
          @"60", 
          @"70", 
          @"80", 
          @"90", 
          @"100", 
          @"150", 
          @"200", 
          @"250", 
          @"300", 
          @"350", 
          @"400", 
          @"450", 
          @"500", 
          @"600", 
          @"700", 
          @"800", 
          @"900", 
          @"1", 
          @"1.5", 
          @"2.0", 
          @"2.5", 
          @"3.0", 
          @"3.5", 
          @"4", 
          @"4.5", 
          @"5", 
          @"5.5", 
          @"6", 
          @"6.5", 
          @"7", 
          @"7.5", 
          @"8", 
          @"8.5", 
          @"9", 
          @"9.5", 
          @"10", 
          @"15", 
          @"20", 
          @"25", 
          @"30", 
          @"35", 
          @"40", 
          @"45", 
          @"50", 
          @"55", 
          @"60", 
          @"65", 
          @"70", 
          @"75", 
          @"80", 
          @"85", 
          @"90", 
          @"95", 
          @"100", 
          @"200", 
          @"300", 
          @"400", 
          @"500", 
          @"600", 
          @"700", 
          @"800", 
          @"900", 
          nil]; 
    return sliderNumbers; 

} 

trên được nạp vào một mảng khi instantiation:

Thiết lập thanh trượt:

customSlider.minimumValue = 0.0f; 
    customSlider.maximumValue = (CGFloat)[sliderNumbers count] - 1; 
    customSlider.continuous = YES; 
    customSlider.value = customSlider.maximumValue; 

Phương pháp kêu gọi UIControlEventValueChanged

- (void) sliderMove:(UISlider*) theSlider { 

    NSInteger numberLookup = lroundf([theSlider value]); 

    NSString *distanceString = [sliderNumbers objectAtIndex:numberLookup]; 
    CGFloat distanceInMeters; 

    if (numberLookup > 21) { 

     [self.indicator.indicatorLabel setText:[NSString stringWithFormat:@"%@ km", distanceString]];  
     distanceInMeters = [distanceString floatValue] * 1000; 
    } else { 

     [self.indicator.indicatorLabel setText:[NSString stringWithFormat:@"%@ m", distanceString]]; 
     distanceInMeters = [distanceString floatValue]; 
    } 

    if (oldDistanceInMeters != distanceInMeters) { 

     [self.delegate distanceSliderChanged:distanceInMeters]; 
     oldDistanceInMeters = distanceInMeters; 
    } 
} 

Điều này thậm chí sẽ chăm sóc của định dạng chuỗi cho giao diện người dùng, ví dụ "200 m" hoặc "1,5 km" và cập nhật đại biểu với số khoảng cách tính bằng mét để sử dụng khi sắp xếp kết quả của tôi với biến vị ngữ.

0

Để làm điều này đúng, bạn muốn thanh trượt của bạn đại diện cho số mũ. Vì vậy, ví dụ nếu bạn muốn có thang điểm từ 10-100000, bạn muốn thanh trượt của mình có phạm vi 1 (10 = 10^1) đến 5 (100.000 = 10^5). Bạn có thể thiết lập bước trên thanh trượt đến một phần nhỏ để cung cấp cho bạn độ chính xác mà bạn muốn. Đối với ví dụ của tôi, tôi sẽ sử dụng tối thiểu 20.000 và tối đa 20.000.000 cho đầu ra (vì đó là những gì tôi cần khi tôi ngồi xuống để tìm ra điều này). Vì tôi về cơ bản sẽ tăng gấp 1000 lần từ tối thiểu đến tối đa tôi muốn 10^3, nên thanh trượt của tôi sẽ là 0-3 (10^0 đánh giá thành 1). Tôi sẽ sử dụng 0,001 bước để có tổng số 3000 vị trí có thể. Đây là mã bạn cần phải thực hiện việc này:

$("#amount-slider").slider({ 
    value:20000, 
    min: 0, 
    max: 3, 
    step:.001, 
    slide: function(event, ui) { 
    $("#amount").val(Math.pow(10, ui.value)*20000); 
    } 
    }); 

Giả sử bạn muốn nghịch đảo của hàm này, do đó bạn có thể đặt vị trí thanh trượt cho một số đầu vào bên ngoài. Sau đó, bạn muốn sử dụng lôgarit:

var amtVal = parseFloat($("#amount").val()); 

    $('#amount-slider').slider('value', ((Math.log(amtVal/20000)/Math.log(10)))); 

Bạn cần điều chỉnh 20000 trong cả hai hàm để khớp với số tiền cơ sở của bạn. Nếu giá trị tối đa của bạn phải được dẫn xuất bởi số mũ của một số khác ngoài 10, thay đổi 10 cũng như số mũ tối đa (số mũ). Cuộc sống sẽ dễ dàng hơn nếu bạn tăng thêm mười sức mạnh.

+2

Đây không phải là câu hỏi javascript ... –

+0

Cảm ơn, hữu ích cho jQuery nhưng không phải là Cocoa Touch! –

2

Bạn cũng có thể thiết lập một "kích thước bước" để xây dựng thanh trượt của bạn như thế này:

- (void) sliderChanged:(UISlider *)slider 
{ 
    int value = (int)[slider value]; 
    int stepSize = 500.0f; 

    value = value - value%stepSize; 

    [km setText:[NSString stringWithFormat:@"%d Km",value]]; 
} 

Cùng với giải pháp này, bạn có thể đặt hai nút (+ và -) để điều chỉnh giá trị thanh trượt của bạn:

- (void) incrementKm:(UIButton *)button 
{ 
    [kmSlider setValue:[kmSlider value] + 500.0f animated:YES]; 
    [self sliderChanged:kmSlider]; 
} 

- (void) decrementKm:(UIButton *)button 
{ 
    [kmSlider setValue:[kmSlider value] - 500.0f animated:YES]; 
    [self sliderChanged:kmSlider]; 
} 
1

Dưới đây là một lựa chọn nếu bạn có một mảng chiều dài thay đổi các tùy chọn mà bạn muốn thanh trượt để chọn:

-(void)setupSlider { 

    //this has to be (scale - 1) from sliderChanged selector to avoid index out of bounds error 
    _sldOptionPicker.maximumValue = 99; 

    //should be zero 
    _sldOptionPicker.minimumValue = 0; 

    //can be any value 0 to 99 
    _sldOptionPicker.value = 0;   

} 

-(IBAction)sliderChanged:(id)sender { 

    float scale = 100/[optionsArray count]; 

    int index = (int)(_sldOptionPicker.value/scale); 

    Option *mySelectedOption = (Option*)[optionsArray objectForIndex:index]; 

} 
Các vấn đề liên quan