Narysuj linię w UIView

86

Muszę narysować poziomą linię w UIView. Jaki jest najłatwiejszy sposób na zrobienie tego. Na przykład chcę narysować czarną poziomą linię przy y -coor = 200.

NIE używam programu Interface Builder.

John Smith
źródło
1
Oto kompletne i łatwe rozwiązanie, aby poprawnie mieć linię jednopikselową we wszystkich systemach iOS i ułatwić tworzenie scenorysu: stackoverflow.com/a/26525466/294884
Fattie

Odpowiedzi:

122

Najłatwiej w twoim przypadku (linia pozioma) jest dodanie widoku podrzędnego z czarnym kolorem tła i ramką [0, 200, 320, 1].

Przykładowy kod (mam nadzieję, że nie ma błędów - napisałem bez Xcode):

UIView *lineView = [[UIView alloc] initWithFrame:CGRectMake(0, 200, self.view.bounds.size.width, 1)];
lineView.backgroundColor = [UIColor blackColor];
[self.view addSubview:lineView];
[lineView release];
// You might also keep a reference to this view 
// if you are about to change its coordinates.
// Just create a member and a property for this...

Innym sposobem jest utworzenie klasy, która będzie narysować linię w swojej metodzie drawRect (widać mój przykładowy kod dla tego tutaj ).

Michael Kessler
źródło
Zrób to bez żadnego kodu w Storyboard. Jest łatwiej i lepiej.
coolcool1994
3
@ coolcool1994, czy nie zauważyłeś „NIE używam programu Interface Builder”. wymóg w pytaniu?
Michael Kessler
312

Może to trochę za późno, ale chcę dodać, że jest lepszy sposób. Korzystanie z UIView jest proste, ale stosunkowo wolne. Ta metoda zastępuje sposób, w jaki widok sam się rysuje i jest szybsza:

- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);

    // Draw them with a 2.0 stroke width so they are a bit more visible.
    CGContextSetLineWidth(context, 2.0f);

    CGContextMoveToPoint(context, 0.0f, 0.0f); //start at this point

    CGContextAddLineToPoint(context, 20.0f, 20.0f); //draw to this point

    // and now draw the Path!
    CGContextStrokePath(context);
}
b123400
źródło
Jeśli ten kod jest używany w UIView, to czy współrzędne w tym przykładzie odnoszą się do granic widoku czy całego ekranu?
ChrisP,
Czy nie trzeba CGContextBeginPath(context);wcześniej dzwonić CGContextMoveToPoint(...);?
i_am_jorf
37
Używanie widoku do tego nie jest straszne. Ułatwia to na przykład wykonywanie niejawnych animacji podczas zmiany orientacji. Jeśli to tylko jeden, kolejny UIView nie jest wcale taki drogi, a kod jest znacznie prostszy.
i_am_jorf
Ponadto za pomocą tych kodów można uzyskać granice i punkt środkowy: CGPoint midPoint; midPoint.x = self.bounds.size.width / 2; midPoint.y = self.bounds.size.height / 2;
coolcool1994
1
Racja, komentarz, że jest „wolny”, nie jest rozsądny. W dowolnym momencie na ekranie pojawia się ogromna liczba prostych podglądów UIV. Zwróć uwagę, że rysowanie JEDNEGO (!) Znaku tekstowego, wraz z całym przetwarzaniem, powoduje, że rysuje wypełniony UIView.
Fattie
30

Swift 3 i Swift 4

W ten sposób możesz narysować szarą linię na końcu widoku (ten sam pomysł, co odpowiedź b123400)

class CustomView: UIView {

    override func draw(_ rect: CGRect) {
        super.draw(rect)
        
        if let context = UIGraphicsGetCurrentContext() {
            context.setStrokeColor(UIColor.gray.cgColor)
            context.setLineWidth(1)
            context.move(to: CGPoint(x: 0, y: bounds.height))
            context.addLine(to: CGPoint(x: bounds.width, y: bounds.height))
            context.strokePath()
        }
    }
}
Guy Daher
źródło
Kontekst „if let” kończy się niepowodzeniem po wywołaniu z viewDidLayoutSubviews.
Oscar
14

Po prostu dodaj etykietę bez tekstu iz kolorem tła. Ustaw wybrane współrzędne, a także wysokość i szerokość. Możesz to zrobić ręcznie lub za pomocą Interface Builder.

Phanindra
źródło
11

Możesz użyć klasy UIBezierPath w tym celu:

I możesz narysować tyle linii, ile chcesz:

Mam podklasę UIView:

    @interface MyLineDrawingView()
    {
       NSMutableArray *pathArray;
       NSMutableDictionary *dict_path;
       CGPoint startPoint, endPoint;
    }

       @property (nonatomic,retain)   UIBezierPath *myPath;
    @end

Zainicjowałem obiekty pathArray i dictPAth, które będą używane do rysowania linii. Piszę główną część kodu z własnego projektu:

- (void)drawRect:(CGRect)rect
{

    for(NSDictionary *_pathDict in pathArray)
    {
        [((UIColor *)[_pathDict valueForKey:@"color"]) setStroke]; // this method will choose the color from the receiver color object (in this case this object is :strokeColor)
        [[_pathDict valueForKey:@"path"] strokeWithBlendMode:kCGBlendModeNormal alpha:1.0];
    }

    [[dict_path objectForKey:@"color"] setStroke]; // this method will choose the color from the receiver color object (in this case this object is :strokeColor)
    [[dict_path objectForKey:@"path"] strokeWithBlendMode:kCGBlendModeNormal alpha:1.0];

}

dotyka metody początkowej:

UITouch *touch = [touches anyObject];
startPoint = [touch locationInView:self];
myPath=[[UIBezierPath alloc]init];
myPath.lineWidth = currentSliderValue*2;
dict_path = [[NSMutableDictionary alloc] init];

dotyka Metoda przeniesiona:

UITouch *touch = [touches anyObject];
endPoint = [touch locationInView:self];

 [myPath removeAllPoints];
        [dict_path removeAllObjects];// remove prev object in dict (this dict is used for current drawing, All past drawings are managed by pathArry)

    // actual drawing
    [myPath moveToPoint:startPoint];
    [myPath addLineToPoint:endPoint];

    [dict_path setValue:myPath forKey:@"path"];
    [dict_path setValue:strokeColor forKey:@"color"];

    //                NSDictionary *tempDict = [NSDictionary dictionaryWithDictionary:dict_path];
    //                [pathArray addObject:tempDict];
    //                [dict_path removeAllObjects];
    [self setNeedsDisplay];

Metoda dotknięcia Ended:

        NSDictionary *tempDict = [NSDictionary dictionaryWithDictionary:dict_path];
        [pathArray addObject:tempDict];
        [dict_path removeAllObjects];
        [self setNeedsDisplay];
YogiAR
źródło
11

Jeszcze jedna (i jeszcze krótsza) możliwość. Jeśli jesteś w drawRect, coś takiego:

[[UIColor blackColor] setFill];
UIRectFill((CGRect){0,200,rect.size.width,1});
hkatz
źródło
0

Na podstawie odpowiedzi Guya Dahera.

Próbuję unikać używania? ponieważ może to spowodować awarię aplikacji, jeśli GetCurrentContext () zwróci nil.

Zrobiłbym zero sprawdzenia, czy oświadczenie:

class CustomView: UIView 
{    
    override func draw(_ rect: CGRect) 
    {
        super.draw(rect)
        if let context = UIGraphicsGetCurrentContext()
        {
            context.setStrokeColor(UIColor.gray.cgColor)
            context.setLineWidth(1)
            context.move(to: CGPoint(x: 0, y: bounds.height))
            context.addLine(to: CGPoint(x: bounds.width, y: bounds.height))
            context.strokePath()
        }
    }
}
Robert Harrold
źródło
2
jeśli powodem ifklauzuli jest po prostu rozpakowanie z opcjonalnego, wolę guardzamiast tego użyć instrukcji.
Julio Flores,
-1

Dodaj etykietę bez tekstu iz kolorem tła odpowiadającym rozmiarowi ramki (np. Wysokość = 1). Zrób to za pomocą kodu lub w konstruktorze interfejsu.

Reddy
źródło