如何在自定义 UIView 中从 ViewController 传递数据

Posted

技术标签:

【中文标题】如何在自定义 UIView 中从 ViewController 传递数据【英文标题】:How to pass data from ViewController in custom UIView 【发布时间】:2015-04-03 15:48:54 【问题描述】:

我的 ViewController 中有一个名为 chordName 的 NSString 变量,它的值是从单独的 TableViewController 中设置的。 我想再次传递此变量,以便在 ViewController 中的自定义视图中使用。

如何从这里传递变量 (viewcontroller.m)

#import "P15ViewController.h"
#import "P15AppDelegate.h"
@interface P15ViewController ()

@end

@implementation P15ViewController

@synthesize intLabel;
@synthesize chordNameLabel;
@synthesize chordName;
- (void)viewDidLoad


    self.guitarStringView.delegate = self;
    chordNameLabel.text = chordName; 
    [super viewDidLoad];



-(void)guitarStringsView:(GuitarStringsView*)view stringPlucked:(int)index withVelocity:(float)velocity;
    
    P15AppDelegate* app = [[UIApplication sharedApplication] delegate];
    [app play:index velocity:velocity];


@end

进入 UIView 类以在 drawRect 方法中使用。 我还是新手,所以如果您需要更多代码,请告诉我。

谢谢

//编辑 - 这是自定义视图类:

.h 

#import <UIKit/UIKit.h>

@class GuitarStringsView;
@protocol GuitarStringsViewDelegate <NSObject>

-(void)guitarStringsView:(GuitarStringsView*)view stringPlucked:(int)index withVelocity:(float)velocity;
@end

@interface GuitarStringsView : UIView

@property (nonatomic) int stringCount;

@property (weak, nonatomic) id <GuitarStringsViewDelegate> delegate;

@end

.m

@interface GuitarStringsView ()
@property (nonatomic, strong) NSMutableArray* touches;
@property (nonatomic, strong) NSMutableArray* timestamps;
@end

@implementation GuitarStringsView

@synthesize stringCount = _stringCount;


- (id)initWithFrame:(CGRect)frame

    if ([super initWithFrame:frame])
    
        [self commonInit];
    

    return self;


- (id)initWithCoder:(NSCoder *)aDecoder

    if ([super initWithCoder:aDecoder])
    
        [self commonInit];
    

    return self;


- (void)commonInit

    // initialise string count and the arrays to log the touches
    self.stringCount = 1;
    self.touches = [[NSMutableArray alloc] initWithCapacity:2];
    self.timestamps = [[NSMutableArray alloc] initWithCapacity:2];


// stringCount getter
-(int)stringCount

    return _stringCount;


// stringCount setter
-(void)setStringCount:(int)stringCount

    // clip to >= 1
    if (stringCount < 1)
        stringCount = 1;

    // if changed
    if (stringCount != _stringCount)
    
        // update
        _stringCount = stringCount;

        // tell the system it needs to redraw this view
        [self setNeedsDisplay];
    


// drawing
- (void)drawRect:(CGRect)rect

    // get the "context" which is the place to which we will draw
    CGContextRef currentContext = UIGraphicsGetCurrentContext();

    // save the state (colours, pen width etc) so we can restore it when we're done
    CGContextSaveGState(currentContext);

    // set up fill and stroke colours
    CGContextSetRGBFillColor(currentContext, 0.5, 0.0, 0.0, 1.0);   // dark red
    CGContextSetRGBStrokeColor(currentContext, 0.0, 0.0, 0.0, 1.0); // black

    // set the stroke pen width
    CGContextSetLineWidth(currentContext, 1);

    // fill whole view with fill colour
    CGContextFillRect(currentContext, rect);

    // calculate geometry, divided screen into N sections where N is stringCount + 1
    const int divisions = self.stringCount + 1;
    const CGFloat divisionWidth = self.bounds.size.width / divisions;

    // start at the first string
    CGFloat stringX = divisionWidth;

    for (int i = 0; i < self.stringCount; ++i, stringX += divisionWidth) // move to next string position each time
    
        // add a line to the path
        CGContextMoveToPoint(currentContext, stringX, 0);
        CGContextAddLineToPoint(currentContext, stringX, self.bounds.size.height);
    

    // draw the path (the strings)
    CGContextStrokePath(currentContext);

    // restore the context
    CGContextRestoreGState(currentContext);

    //Draw frets
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetLineWidth(context, 2.0);
    CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
    CGFloat components[] = 0.0, 0.0, 1.0, 1.0;
    CGColorRef color = CGColorCreate(colorspace, components);
    CGContextSetStrokeColorWithColor(context, color);
    for (int i = 1; i < 5; ++i) // move to next fret position each time
    
        // add a line to the path
        CGContextMoveToPoint(context, 1, (i * 100));
        CGContextAddLineToPoint(context, 300, (i * 100));
    

    CGContextStrokePath(context);
    CGColorSpaceRelease(colorspace);
    CGColorRelease(color);


    //draw finger markers
    CGColorRef red = [[UIColor redColor] CGColor];
    CGContextRef fingerContext = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(fingerContext, red);
    CGContextFillEllipseInRect(context, CGRectMake(60, 140, 40, 40));





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

    // iterate over the touches
    for (UITouch* touch in touches)
    
        // find just the touches that have just begun (finger down)
        if (touch.phase == UITouchPhaseBegan)
        
            // add the touch to the touches array
            [self.touches addObject:touch];

            // get the timestamp of the touch and add that as an NSNumber to the timestamps array
            NSNumber* timestamp = [NSNumber numberWithDouble:touch.timestamp];
            [self.timestamps addObject:timestamp];
        
    


- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event

    // calculate geometry, divided screen into N sections where N is stringCount + 1
    const int divisions = self.stringCount + 1;
    const CGFloat divisionWidth = self.bounds.size.width / divisions;

    // iterate over the touches
    for (UITouch* touch in touches)
    
        // find just the touches that have just moved 
        if (touch.phase == UITouchPhaseMoved)
        
            // compare the timestamps of the last time we saw this touch and now
            // to get the duration since we last saw this touch
            const int timestampIndex = [self.touches indexOfObject:touch];
            NSNumber* prevTimestampObject = self.timestamps[timestampIndex];

            const NSTimeInterval prevTimestamp = [prevTimestampObject doubleValue];
            const NSTimeInterval thisTimestamp = touch.timestamp;
            const NSTimeInterval duration = thisTimestamp - prevTimestamp;

            // get the previous and current x positions of this touch
            const CGFloat hereX = [touch locationInView:self].x;
            const CGFloat prevX = [touch previousLocationInView:self].x;

            CGFloat stringX = divisionWidth;

            // iterate over the strings
            for (int i = 0; i < self.stringCount; ++i, stringX += divisionWidth)
            
                // did the touch cross this string since the last time we saw this touch?
                if (((prevX < stringX) && (hereX >= stringX)) ||
                    ((prevX > stringX) && (hereX <= stringX)))
                
                    // calculate a velocity value based on the speed the finger was moving
                    const CGFloat distance = fabsf (hereX - prevX) / self.bounds.size.width;
                    const CGFloat velocity = (distance / duration) / self.stringCount;

                    // send the pluck message to our delegate, clipping velocity to <= 1
                    [self.delegate guitarStringsView:self
                                       stringPlucked:i
                                        withVelocity:velocity < 1 ? velocity : 1.f];
                
            

            // update the strored timestamp for this touch for next time
            self.timestamps[timestampIndex] = [NSNumber numberWithDouble:thisTimestamp];
        
    


- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event

    // iterate over the touches
    for (UITouch* touch in touches)
    
        // just get touches that have ended or have been cancelled
        if ((touch.phase == UITouchPhaseEnded) ||
            (touch.phase == UITouchPhaseCancelled))
        
            // get the index of this touch in our touches array
            const int index = [self.touches indexOfObject:touch];

            // remove the touch from the touches array
            [self.touches removeObjectAtIndex:index];

            // remove the associated timestamp
            [self.timestamps removeObjectAtIndex:index];
        
    


- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event

    // do same as touchesEnded: in this case
    [self touchesEnded:touches withEvent:event];



@end

【问题讨论】:

请同时添加您的自定义视图代码。届时我们可以为您提供更好的帮助。 已将其添加到问题中 我已经添加了一个答案。请检查。 【参考方案1】:

以下是您需要在 GuitarStringsView 中进行的更改

#import <UIKit/UIKit.h>
@class GuitarStringsView;
@protocol GuitarStringsViewDelegate <NSObject>
-(void)guitarStringsView:(GuitarStringsView*)view stringPlucked:(int)index withVelocity:(float)velocity;
@end

@interface GuitarStringsView : UIView
@property (nonatomic) int stringCount;
@property(nonatomic) NSString *chordName;
@property (weak, nonatomic) id <GuitarStringsViewDelegate> delegate;
@end

接下来你可以在你的视图控制器中设置viewDidLoad:方法

self.guitarStringView.chordName = chordName;

【讨论】:

【参考方案2】:

如果您的自定义 UIView 显示在您的 UIViewController 中,您应该为您的 UIView 提供一个自定义类,其中包含一个名为 chordName 的属性。您的 UIViewController 应该访问您的 UIView 并将其属性设置为新的 chordName。 你的代码会是这样的

Declare CustomView *myCustomView in your header file
myCustomView = [CustomView new];
[self.view addsubview:myCustomView]

现在需要时,您可以通过以下方式设置值 myCustomView.chordValue = chordValue

【讨论】:

我确实有一个用于该 UIView 的自定义类,但我将如何访问该视图并设置其属性? 你的这个自定义视图,它添加在哪里?是否添加到同一个 UIViewController 中? 是的,它与我希望传递的变量在同一个 ViewController 中

以上是关于如何在自定义 UIView 中从 ViewController 传递数据的主要内容,如果未能解决你的问题,请参考以下文章

如何在自定义混合任务中从 Ecto 获取数据

如何在自定义 Zapier 应用程序中从 Xero 访问特定订单项值?

如何在自定义 UIView 中添加 UITableView?

如何借助 AutoLayout 在自定义 UITableviewCell 中添加自定义 UIView(xib)?

如何让 UITableViewCell 在自定义 UIView 子类上调用 setHighlighted 或 setSelected?

如何在自定义 UIView 下方的 MKMapview 中启用 touchEvents(滚动和平移)?