2013-10-02 11 views
18

chcę dać następujący aspekt do UISegmentedControl:UISegmentedControl granice

enter image description here

Uwaga szare tło widoku i białe tło segmentowej kontroli non wybranego elementu.

Ale jeśli dam białe tło do mojego UISegmentedControl, mam następujące:

enter image description here

Uwaga białe kwadratowe rogi wokół UISegmentedControl. Co powinienem zrobić, aby ominąć te kwadratowe rogi?

Dziękuję z góry,

EDIT: Jeśli zmienić promień narożnika warstwie UISegmentedControl, tak jak sugeruje onegray, wynik jest lepszy, ale nie idealny (uwaga na białą linię po prawej):

enter image description here

+0

można ustawić 'segmented.backgroundColor = [UIColor clearColor];' –

+0

@Viruss MCA: Dziękuję za komentarz, ale w tym przypadku, tło za "Tratad jako "jest pokazane na szaro, a nie na biało. – neutrino

+0

Możesz również użyć dwóch UIButtons zamiast UISegmentedControl jako alternatywnego rozwiązania. – Engnyl

Odpowiedz

10

Jeśli to powinien działać na wszystkich UISegmentedControls to trochę kłopotów. Problem dotyczy iOS7 1 pt. granica między dwoma segmentami nie liczy się z rozmiarem segmentu. Na przykład. jeśli rama twojego UISegmentedControl wynosi 320 pt. szeroki musisz usunąć 1 pt. a następnie podzielić przez 2. A (320-1)/2 to 159,5. System iOS stosuje tę wartość do 159 punktów. I kończysz z 1 pkt. granica i dwie 159 pt. segmenty. Który jest 319, a nie 320. Stąd 1pt. linia po prawej stronie segmentedControl.

Istnieje sposób obliczania "rzeczywistego" (rozmiar renderowania na ekranie) rozmiaru segmentedControl. Dzięki tej szerokości możesz dodać UIView z zaokrąglonymi narożnikami poniżej UISegmentedControl. Kod ten powinien działać na wszystkich konfiguracjach, nawet jeśli trzeba ręcznie wielkości segmenty w segmentedControl:

- (UIView *)addBackgroundViewBelowSegmentedControl:(UISegmentedControl *)segmentedControl { 
    CGFloat autosizedWidth = CGRectGetWidth(segmentedControl.bounds); 
    autosizedWidth -= (segmentedControl.numberOfSegments - 1); // ignore the 1pt. borders between segments 

    NSInteger numberOfAutosizedSegmentes = 0; 
    NSMutableArray *segmentWidths = [NSMutableArray arrayWithCapacity:segmentedControl.numberOfSegments]; 
    for (NSInteger i = 0; i < segmentedControl.numberOfSegments; i++) { 
     CGFloat width = [segmentedControl widthForSegmentAtIndex:i]; 
     if (width == 0.0f) { 
      // auto sized 
      numberOfAutosizedSegmentes++; 
      [segmentWidths addObject:[NSNull null]]; 
     } 
     else { 
      // manually sized 
      autosizedWidth -= width; 
      [segmentWidths addObject:@(width)]; 
     } 
    } 

    CGFloat autoWidth = floorf(autosizedWidth/(float)numberOfAutosizedSegmentes); 
    CGFloat realWidth = (segmentedControl.numberOfSegments-1);  // add all the 1pt. borders between the segments 
    for (NSInteger i = 0; i < [segmentWidths count]; i++) { 
     id width = segmentWidths[i]; 
     if (width == [NSNull null]) { 
      realWidth += autoWidth; 
     } 
     else { 
      realWidth += [width floatValue]; 
     } 
    } 

    CGRect whiteViewFrame = segmentedControl.frame; 
    whiteViewFrame.size.width = realWidth; 

    UIView *whiteView = [[UIView alloc] initWithFrame:whiteViewFrame]; 
    whiteView.backgroundColor = [UIColor whiteColor]; 
    whiteView.layer.cornerRadius = 5.0f; 
    [self.view insertSubview:whiteView belowSubview:segmentedControl]; 
    return whiteView; 
} 

Proszę dbać ramki zmienia się.

Zobacz ten zrzut ekranu, aby zobaczyć różnicę między dwoma elementami sterującymi. Wszystkie ramki mają 280 pt. szeroki.

Ze względu na formułę UISegmentedControl używa pierwszych kontrolek, rzeczywisty rozmiar to 278 pt. A rzeczywista wielkość drugiego to 279 pt.

enter image description here


Problemem jest to, że w jakiś sposób polega na realizacji UISegmentedControl. Apple może na przykład zmienić implementację, tak aby segmentWidth, który kończy się na .5 punktach, zostanie wyświetlony. Mogli to łatwo zrobić na wyświetlaczach Retina.

Jeśli używasz tego kodu, powinieneś jak najszybciej sprawdzić swoją aplikację na nowych wersjach systemu iOS. Opieramy się na szczegółach wdrożenia, a te mogą się zmieniać każdego dnia. Na szczęście nic się nie dzieje, jeśli zmieniają implementację. Po prostu nie będzie dobrze.

+0

Dziękuję bardzo! To działa dobrze. I dałeś świetne wyjaśnienie. – neutrino

16

Ustawianie _segmentedControl.layer.cornerRadius = 5; może pomóc.

Aktualizacja: Bardziej skomplikowane klip rect pozbyć 1px prawej przestrzeni:

CAShapeLayer* mask = [[CAShapeLayer alloc] init]; 
    mask.frame = CGRectMake(0, 0, _segmentedControl.bounds.size.width-1, _segmentedControl.bounds.size.height); 
    mask.path = [[UIBezierPath bezierPathWithRoundedRect:mask.frame cornerRadius:4] CGPath]; 
    _segmentedControl.layer.mask = mask; 

Aktualizacja: Matthias Bauch warunkiem dobrego wyjaśnienia dlaczego po prawej stronie pojawi się ten UISegmentedControl spacje. Tak więc najprostszym sposobem na jej usunięcie jest wykonanie segmentów o stałym rozmiarze i dostosowanie ich do właściwej szerokości.

+0

Dziękuję za odpowiedź. Dzięki temu wynik jest lepszy, ale daleki od doskonałości. Zobacz zdjęcie załączone w moim oryginalnym poście. – neutrino

+0

Jeszcze raz dziękuję. W końcu poszedłem z odpowiedzią Matthiasa, ale bardzo mi pomogłeś. Przetestowałem Twoje rozwiązanie i działa ono również dla mnie. – neutrino

+0

Świetne rozwiązanie. Dzięki!!! –

2

Wiem, że to rodzaj hackowania, ale wystarczy użyć zaokrąglonego UIView z białym tłem umieszczonym tuż pod - i wyrównanym - z segmentowanym sterowaniem, z wyjątkiem szerokości, która powinna być równa oryginalnej szerokości kontrolki minus 1 .

Wynik: Segmented Control with White Background

+0

Jeśli używasz opcji Autolayout, możesz przypiąć "widok w tle", aby dopasować szerokość/wysokość itp. SegmentControl, więc nie trzeba dostosowywać się za pomocą znaku minus 1. Oczywiście można również użyć atrybutów środowiska wykonawczego, aby ustawić róg Radiusa w widoku tła – wuf810

0

Tylko do wyjaśnić doskonałą odpowiedź Mattias Bauch. Trzeba ustawić wracającą widok jako widok podrzędny do widoku (które nazywane yourMainView), gdzie masz swój segmentową sterowania:

UIView *segmControlBackground = [self addBackgroundViewBelowSegmentedControl:yourSegmentedControl]; 
[yourMainView addSubview:segmControlBackground]; 



i trzeba oczywiście zadeklarować nowa metoda w pliku nagłówka (.h):

- (UIView *)addBackgroundViewBelowSegmentedControl:(UISegmentedControl *)segmentedControl;