Jak mogę zmienić kolor kropek stronicowania w UIPageControl?

178

Tworzę aplikację, w której chcę zmienić kolor lub obraz UIPageControlkropek stronicowania. Jak mogę to zmienić? Czy można dostosować UIpageControlpowyższy scenariusz?

Tirth
źródło

Odpowiedzi:

266

AKTUALIZACJA:

Ta odpowiedź ma 6 lat i jest bardzo nieaktualna, ale wciąż przyciąga głosy i komentarze. Od wersji iOS 6.0 powinieneś używać właściwości pageIndicatorTintColori .currentPageIndicatorTintColorUIPageControl

ORYGINALNA ODPOWIEDŹ:

Wpadłem dzisiaj na ten problem i postanowiłem napisać własną prostą klasę zastępczą.

Jest to sublasowany UIView, który używa Core Graphics do renderowania kropek w określonych przez Ciebie kolorach.

Za pomocą ujawnionych właściwości można go dostosowywać i kontrolować.

Jeśli chcesz, możesz zarejestrować obiekt delegowany, aby otrzymywać powiadomienia, gdy użytkownik stuknie jedną z małych kropek strony. Jeśli nie zostanie zarejestrowany żaden uczestnik, widok nie zareaguje na wprowadzanie dotykowe.

Z piekarnika jest całkowicie świeży, ale wydaje się, że działa. Daj mi znać, jeśli napotkasz jakieś problemy.

Przyszłe ulepszenia:

  • Zmień rozmiar kropek, aby dopasować je do bieżących granic, jeśli jest ich zbyt wiele.
  • Nie przerysowuj całego widoku w drawRect:

Przykładowe zastosowanie:

CGRect f = CGRectMake(0, 0, 320, 20); 
PageControl *pageControl = [[[PageControl alloc] initWithFrame:f] autorelease];
pageControl.numberOfPages = 10;
pageControl.currentPage = 5;
pageControl.delegate = self;
[self addSubview:pageControl];

Plik nagłówka:

//
//  PageControl.h
//
//  Replacement for UIPageControl because that one only supports white dots.
//
//  Created by Morten Heiberg <[email protected]> on November 1, 2010.
//

#import <UIKit/UIKit.h>

@protocol PageControlDelegate;

@interface PageControl : UIView 
{
@private
    NSInteger _currentPage;
    NSInteger _numberOfPages;
    UIColor *dotColorCurrentPage;
    UIColor *dotColorOtherPage;
    NSObject<PageControlDelegate> *delegate;
    //If ARC use __unsafe_unretained id delegate;
}

// Set these to control the PageControl.
@property (nonatomic) NSInteger currentPage;
@property (nonatomic) NSInteger numberOfPages;

// Customize these as well as the backgroundColor property.
@property (nonatomic, retain) UIColor *dotColorCurrentPage;
@property (nonatomic, retain) UIColor *dotColorOtherPage;

// Optional delegate for callbacks when user taps a page dot.
@property (nonatomic, retain) NSObject<PageControlDelegate> *delegate;

@end

@protocol PageControlDelegate<NSObject>
@optional
- (void)pageControlPageDidChange:(PageControl *)pageControl;
@end

Plik implementacyjny:

//
//  PageControl.m
//
//  Replacement for UIPageControl because that one only supports white dots.
//
//  Created by Morten Heiberg <[email protected]> on November 1, 2010.
//

#import "PageControl.h"

// Tweak these or make them dynamic.
#define kDotDiameter 7.0
#define kDotSpacer 7.0

@implementation PageControl

@synthesize dotColorCurrentPage;
@synthesize dotColorOtherPage;
@synthesize delegate;

- (NSInteger)currentPage
{
    return _currentPage;
}

- (void)setCurrentPage:(NSInteger)page
{
    _currentPage = MIN(MAX(0, page), _numberOfPages-1);
    [self setNeedsDisplay];
}

- (NSInteger)numberOfPages
{
    return _numberOfPages;
}

- (void)setNumberOfPages:(NSInteger)pages
{
    _numberOfPages = MAX(0, pages);
    _currentPage = MIN(MAX(0, _currentPage), _numberOfPages-1);
    [self setNeedsDisplay];
}

    - (id)initWithFrame:(CGRect)frame
{
    if ((self = [super initWithFrame:frame]))
    {
        // Default colors.
        self.backgroundColor = [UIColor clearColor];
        self.dotColorCurrentPage = [UIColor blackColor];
        self.dotColorOtherPage = [UIColor lightGrayColor];

        UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipedRight:)];
        [swipeRight setDirection:UISwipeGestureRecognizerDirectionRight];
        [self addGestureRecognizer:swipeRight];




        UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipedLeft:)];
        [swipe setDirection:UISwipeGestureRecognizerDirectionLeft];
        [self addGestureRecognizer:swipe];

    }
    return self;
}
-(void) swipedLeft:(UISwipeGestureRecognizer *) recognizer
{
    self.currentPage++;
}
-(void) swipedRight:(UISwipeGestureRecognizer *) recognizer
{
    self.currentPage--;
}

- (void)drawRect:(CGRect)rect 
{
    CGContextRef context = UIGraphicsGetCurrentContext();   
    CGContextSetAllowsAntialiasing(context, true);

    CGRect currentBounds = self.bounds;
    CGFloat dotsWidth = self.numberOfPages*kDotDiameter + MAX(0, self.numberOfPages-1)*kDotSpacer;
    CGFloat x = CGRectGetMidX(currentBounds)-dotsWidth/2;
    CGFloat y = CGRectGetMidY(currentBounds)-kDotDiameter/2;
    for (int i=0; i<_numberOfPages; i++)
    {
        CGRect circleRect = CGRectMake(x, y, kDotDiameter, kDotDiameter);
        if (i == _currentPage)
        {
            CGContextSetFillColorWithColor(context, self.dotColorCurrentPage.CGColor);
        }
        else
        {
            CGContextSetFillColorWithColor(context, self.dotColorOtherPage.CGColor);
        }
        CGContextFillEllipseInRect(context, circleRect);
        x += kDotDiameter + kDotSpacer;
    }
}

- (void)dealloc 
{
    [dotColorCurrentPage release];
    [dotColorOtherPage release];
    [delegate release];
    [super dealloc];
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    if (!self.delegate) return;

    CGPoint touchPoint = [[[event touchesForView:self] anyObject] locationInView:self];

    CGFloat dotSpanX = self.numberOfPages*(kDotDiameter + kDotSpacer);
    CGFloat dotSpanY = kDotDiameter + kDotSpacer;

    CGRect currentBounds = self.bounds;
    CGFloat x = touchPoint.x + dotSpanX/2 - CGRectGetMidX(currentBounds);
    CGFloat y = touchPoint.y + dotSpanY/2 - CGRectGetMidY(currentBounds);

    if ((x<0) || (x>dotSpanX) || (y<0) || (y>dotSpanY)) return;

    self.currentPage = floor(x/(kDotDiameter+kDotSpacer));
    if ([self.delegate respondsToSelector:@selector(pageControlPageDidChange:)])
    {
        [self.delegate pageControlPageDidChange:self];
    }
}

@end
Heiberg
źródło
Jak to działa? Używam metody pagecontrolPageDidChange i nic nie otrzymuję. Nie mogę kliknąć żadnego z przycisków
Adam
Cześć Heiberg, użyłem tego, aby zmienić stronę przewijania, jak to zrobić ze swojego kodu? [pageControl1 addTarget: self action: @selector (changePage :) forControlEvents: UIControlEventValueChanged];
Desmond
// Akcja zmiany strony na UIPageControl - (void) changePage: (UIPageControl *) control {// int page = pageControl.currentPage; int page = pageControl.currentPage; // zaktualizuj widok przewijania do odpowiedniej strony CGRect frame = scrollview.frame; frame.origin.x = frame.size.width * strona; frame.origin.y = 0; [scrollview scrollRectToVisible: animowana ramka: TAK]; pageControlUsed = TAK; }
Desmond
Aby uruchomić ten kod z ARC, wystarczy usunąć metodę dealloc, zmienić przypisanie na słaby i dodać __weak przed zgłoszeniem właściwości. Bardzo dobrze. Wielkie dzięki.
cschuff,
zamień NSObject <PageControlDelegate> * delegate na __unsafe_unretained id delegate; w nagłówku, aby rozwiązać ostrzeżenie ARC
Mihir Mehta
150

W iOS 6 możesz ustawić kolor odcienia UIPageControl:

Istnieją 2 nowe właściwości:

  • pageIndicatorTintColor
  • currentPageIndicatorTintColor

Możesz także użyć interfejsu API wyglądu, aby zmienić kolor odcienia wszystkich wskaźników strony.

Jeśli celujesz w iOS 5, upewnij się, że się nie zawiesi:

if ([pageControl respondsToSelector:@selector(setPageIndicatorTintColor:)]) {
    pageControl.pageIndicatorTintColor = [UIColor whiteColor];
}
Felix
źródło
Co z iOS 5? Jak się upewnić, że to się nie zawiesi?
jjxtra 21.04.13
41
pageControl.pageIndicatorTintColor = [UIColor redColor];
pageControl.currentPageIndicatorTintColor = [UIColor redColor];

działa na iOS6

Add080bbA
źródło
2
Byłem zaskoczony, że będę musiał podklasować UIPageControl. To załatwiło sprawę. Powinno to być na pozycji nr 1.
Forrest
Dlaczego tak złożona odpowiedź jest najczęściej wybierana, gdy jest to dosłownie wszystko, czego potrzebujesz?
TaylorAllred
23

W przypadku, gdy ktoś chce ARC / jego nowoczesnej wersji (nie trzeba ponownie definiować właściwości jako ivar, bez dealloc i współpracuje z Konstruktorem interfejsów):

#import <UIKit/UIKit.h>

@protocol PageControlDelegate;

@interface PageControl : UIView 

// Set these to control the PageControl.
@property (nonatomic) NSInteger currentPage;
@property (nonatomic) NSInteger numberOfPages;

// Customize these as well as the backgroundColor property.
@property (nonatomic, strong) UIColor *dotColorCurrentPage;
@property (nonatomic, strong) UIColor *dotColorOtherPage;

// Optional delegate for callbacks when user taps a page dot.
@property (nonatomic, weak) NSObject<PageControlDelegate> *delegate;

@end

@protocol PageControlDelegate<NSObject>
@optional
- (void)pageControlPageDidChange:(PageControl *)pageControl;
@end

PageControl.m:

#import "PageControl.h"


// Tweak these or make them dynamic.
#define kDotDiameter 7.0
#define kDotSpacer 7.0

@implementation PageControl

@synthesize dotColorCurrentPage;
@synthesize dotColorOtherPage;
@synthesize currentPage;
@synthesize numberOfPages;
@synthesize delegate;

- (void)setCurrentPage:(NSInteger)page
{
    currentPage = MIN(MAX(0, page), self.numberOfPages-1);
    [self setNeedsDisplay];
}

- (void)setNumberOfPages:(NSInteger)pages
{
    numberOfPages = MAX(0, pages);
    currentPage = MIN(MAX(0, self.currentPage), numberOfPages-1);
    [self setNeedsDisplay];
}

- (id)initWithFrame:(CGRect)frame 
{
    if (self = [super initWithFrame:frame]) 
    {
        // Default colors.
        self.backgroundColor = [UIColor clearColor];
        self.dotColorCurrentPage = [UIColor blackColor];
        self.dotColorOtherPage = [UIColor lightGrayColor];
    }
    return self;
}

-(id)initWithCoder:(NSCoder *)aDecoder
{
    if (self = [super initWithCoder:aDecoder])
    {
        self.dotColorCurrentPage = [UIColor blackColor];
        self.dotColorOtherPage = [UIColor lightGrayColor];
    }
    return self;
}

- (void)drawRect:(CGRect)rect 
{
    CGContextRef context = UIGraphicsGetCurrentContext();   
    CGContextSetAllowsAntialiasing(context, true);

    CGRect currentBounds = self.bounds;
    CGFloat dotsWidth = self.numberOfPages*kDotDiameter + MAX(0, self.numberOfPages-1)*kDotSpacer;
    CGFloat x = CGRectGetMidX(currentBounds)-dotsWidth/2;
    CGFloat y = CGRectGetMidY(currentBounds)-kDotDiameter/2;
    for (int i=0; i<self.numberOfPages; i++)
    {
        CGRect circleRect = CGRectMake(x, y, kDotDiameter, kDotDiameter);
        if (i == self.currentPage)
        {
            CGContextSetFillColorWithColor(context, self.dotColorCurrentPage.CGColor);
        }
        else
        {
            CGContextSetFillColorWithColor(context, self.dotColorOtherPage.CGColor);
        }
        CGContextFillEllipseInRect(context, circleRect);
        x += kDotDiameter + kDotSpacer;
    }
}


- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    if (!self.delegate) return;

    CGPoint touchPoint = [[[event touchesForView:self] anyObject] locationInView:self];

    CGFloat dotSpanX = self.numberOfPages*(kDotDiameter + kDotSpacer);
    CGFloat dotSpanY = kDotDiameter + kDotSpacer;

    CGRect currentBounds = self.bounds;
    CGFloat x = touchPoint.x + dotSpanX/2 - CGRectGetMidX(currentBounds);
    CGFloat y = touchPoint.y + dotSpanY/2 - CGRectGetMidY(currentBounds);

    if ((x<0) || (x>dotSpanX) || (y<0) || (y>dotSpanY)) return;

    self.currentPage = floor(x/(kDotDiameter+kDotSpacer));
    if ([self.delegate respondsToSelector:@selector(pageControlPageDidChange:)])
    {
        [self.delegate pageControlPageDidChange:self];
    }
}

@end
Ben G.
źródło
1
Drobny dodatek, aby zatrzymać wysyłanie do delegata, jeśli numer strony nie zmienił się po dotknięciu. NSInteger newPage = floor (x / (kDotDiameter + kDotSpacer)); if (self.currentPage == newPage) zwraca;
theLastNightTrain
15

Odpowiedź udzielona przez Heiberga działa naprawdę dobrze, jednak kontrola strony nie zachowuje się dokładnie tak samo jak Apple.

Jeśli chcesz, aby formant strony zachowywał się tak, jak ma to miejsce w przypadku Apple (zawsze zwiększaj bieżącą stronę o jedną, jeśli dotkniesz drugiej połowy, w przeciwnym razie zmniejsz o jedną), spróbuj zamiast tego dotknąć metody Began:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{

    CGPoint touchPoint = [[[event touchesForView:self] anyObject] locationInView:self];

    CGRect currentBounds = self.bounds;
    CGFloat x = touchPoint.x - CGRectGetMidX(currentBounds);

    if(x<0 && self.currentPage>=0){
        self.currentPage--;
        [self.delegate pageControlPageDidChange:self]; 
    }
    else if(x>0 && self.currentPage<self.numberOfPages-1){
        self.currentPage++;
        [self.delegate pageControlPageDidChange:self]; 
    }   
}
ChristophK
źródło
8

Dodaj następujący kod do DidFinishLauch w AppDelegate,

UIPageControl *pageControl = [UIPageControl appearance];
pageControl.pageIndicatorTintColor = [UIColor lightGrayColor];
pageControl.currentPageIndicatorTintColor = [UIColor blackColor];
pageControl.backgroundColor = [UIColor whiteColor];

Mam nadzieję, że to pomoże.

posha
źródło
6

użyj tego do kodowania

if ([pageControl respondsToSelector:@selector(setPageIndicatorTintColor:)]) {
    pageControl.pageIndicatorTintColor = [UIColor whiteColor];
}

lub z serii ujęć możesz zmienić bieżący odcień strony

wprowadź opis zdjęcia tutaj

Pooja Patel
źródło
Dzięki ... dziel się dalej :)
Tirth,
6

W Swift ten kod wewnątrz UIPageViewController otrzymuje odniesienie do wskaźnika strony i ustawia jego właściwości

override func viewDidLoad() {
    super.viewDidLoad()

    //Creating the proxy
    let pageControl = UIPageControl.appearance()
    //Customizing
    pageControl.pageIndicatorTintColor = UIColor.lightGrayColor()
    pageControl.currentPageIndicatorTintColor = UIColor.darkGrayColor()
    //Setting the background of the view controller so the dots wont be on a black background   
    self.view.backgroundColor = UIColor.whiteColor()
}
arbel03
źródło
UIPageControlto nie to samo, coUIPageViewController
jungledev
5

Dodając do istniejących odpowiedzi, można to zrobić w następujący sposób:

wprowadź opis zdjęcia tutaj

a do Z
źródło
4

Z Swift 1.2 jest to łatwe:

UIPageControl.appearance().pageIndicatorTintColor           = UIColor.lightGrayColor()
UIPageControl.appearance().currentPageIndicatorTintColor    = UIColor.redColor()
Oleg Popow
źródło
3
Ustawia to globalnie. Jeśli masz wiele aplikacji UIPageControl i potrzebujesz różnych kolorów w zależności od klasy, użyj UIPageControl.appearanceWhenContainedInInstancesOfClasses([MyClassName.self])zamiast UIPageControl.appearance(). Wymaga systemu iOS 9.
Jon
4

Możesz to łatwo naprawić, dodając następujący kod do pliku appdelegate.m w didFinishLaunchingWithOptionsmetodzie:

UIPageControl *pageControl = [UIPageControl appearance];
pageControl.pageIndicatorTintColor = [UIColor darkGrayColor];
pageControl.currentPageIndicatorTintColor = [UIColor orangeColor];
pageControl.backgroundColor = [UIColor whiteColor]
Nabil El Atlas
źródło
3

To działa dla mnie w iOS 7.

pageControl.pageIndicatorTintColor = [UIColor purpleColor];
pageControl.currentPageIndicatorTintColor = [UIColor magentaColor];
Sid
źródło
2

Z oficjalnego punktu widzenia nie można korzystać z iPhone SDK. Być może będziesz w stanie to zrobić za pomocą prywatnych metod, ale będzie to stanowić barierę przed wejściem do sklepu z aplikacjami.

Jedynym innym bezpiecznym rozwiązaniem jest utworzenie własnej kontroli strony, która nie powinna być zbyt trudna, biorąc pod uwagę, że kontrola strony pokazuje po prostu, która strona jest aktualnie wyświetlana w widoku przewijania.

Jasarien
źródło
To nie jest link do mojego rozwiązania. Moje rozwiązanie znajduje się w tekście tuż nad komentarzem. Poszukaj prywatnych metod (nie będę wiedział, co to są) lub napisz własne (nie zrobię tego dla ciebie).
Jasarien
2

@Jasarien Myślę, że można podklasować UIPageControll, linia wybrana tylko z Apple Doc „Podklasy, które dostosowują wygląd formantu strony, mogą użyć tej metody do zmiany rozmiaru formantu strony, gdy zmienia się liczba stron” dla metody sizeForNumberOfPages:

dsaw
źródło
2

Możesz także użyć biblioteki Three20, która zawiera stylowy PageControl oraz dziesiątki innych przydatnych kontrolek i abstrakcji interfejsu użytkownika.

cschuff
źródło
2

W przypadku Swift 2.0wzwyż i niżej poniższy kod będzie działał:

pageControl.pageIndicatorTintColor = UIColor.whiteColor()
pageControl.currentPageIndicatorTintColor = UIColor.redColor()
Sohil R. Memon
źródło
-1
myView.superview.tintColor = [UIColor colorWithRed:1.0f  
                                      green:1.0f blue:1.0f alpha:1.0f];
Michael Belanger
źródło