2 Stimmen

Erstellen einer benutzerdefinierten UIButton-Klasse mit Löschfunktion

Ich habe ein Raster von UIButtons. Wenn ich auf eine Schaltfläche "Bearbeiten" drücke, möchte ich, dass über jeder dieser Schaltflächen eine Löschschaltfläche erscheint, die, wenn sie gedrückt wird, die Schaltfläche (und die zugehörigen Daten) löscht. Ein bisschen wie Apples Home-Bildschirm, wenn Sie eine Schaltfläche gedrückt halten und es beginnt zu wackeln mit einem X in der Ecke.

Laut diesem Beitrag: Unterklasse UIButton zum Hinzufügen einer Eigenschaft Ich kann assoziative Verweise verwenden, um jeder meiner Schaltflächen eine Eigenschaft hinzuzufügen. Ich habe versucht, eine UIButton als Eigenschaft meiner benutzerdefinierten UIButton hinzufügen, aber ich kann nicht scheinen, um es zu erscheinen und haben das Gefühl, dies ist nicht der richtige Weg zu gehen. Hier ist meine benutzerdefinierte Schaltfläche main:

    #import "UIButton+Property.h"
#import <objc/runtime.h>

@implementation UIButton(Property)

static char UIB_DELETEBUTTON_KEY;

@dynamic deleteButton;

- (void)setDeleteButton:(UIButton *)deleteButton {
    deleteButton = [UIButton buttonWithType:UIButtonTypeInfoDark];
    deleteButton.frame = CGRectMake(100, 100, 50, 50);
    objc_setAssociatedObject(self, &UIB_DELETEBUTTON_KEY, deleteButton, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (UIButton *)deleteButton {
    return (UIButton *)objc_getAssociatedObject(self, &UIB_DELETEBUTTON_KEY);
}

@end

Und hier füge ich die Schaltflächen programmatisch hinzu:

//Create a custom button for each custom book doc
for (int i = 0; i < [customBookDocs count]; ++i) {
    BookDoc *customBookDoc = [customBookDocs objectAtIndex:i];
    NSString *bookTitle = customBookDoc.book.title;

    //create a button for each book
    CGRect frame = CGRectMake(xCoord, yCoord, 200, 200);
    UIButton *bookButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    bookButton.bookDoc = customBookDoc;
    [bookButton setFrame:frame];
    [bookButton setTitle:bookTitle forState:UIControlStateNormal];
    [bookButton addTarget:self action:@selector(bookButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
    xCoord += 250;

    [self.view addSubview:bookButton];
    [self.view addSubview:bookButton.deleteButton];
}

Gibt es eine einfachere und sinnvollere Möglichkeit, dies zu tun? Oder bin ich auf dem richtigen Weg?

1voto

strings42 Punkte 533

URSPRÜNGLICHE ANTWORT BEGANN:

... Vielleicht hat jemand anderes mehr dazu zu sagen, aber ich bin mir nicht sicher, warum Sie hier die Objektzuordnung verwenden müssen. Sie können sicherlich eine andere Schaltfläche zu Ihrer Schaltfläche als eine Eigenschaft hinzufügen, indem Sie eine reguläre Unterklasse verwenden, was der Weg ist, den ich nehmen würde. ...

EDITS BELOW:

Ich dachte, ich hätte ein UI-Steuerelement direkt unterklassifiziert, aber als ich nach dem Code suchte, stellte ich fest, dass ich mich geirrt hatte. @Joe hat in den Kommentaren zu Recht darauf hingewiesen, dass es Probleme mit der direkten Unterklassifizierung von UI-Steuerelementen gibt.

Ich war in der Lage, so etwas wie die Funktionalität, die Sie beschrieben haben, zu implementieren, ohne Associated Objects zu verwenden, indem ich eine Wrapper-Klasse erstellt habe, die die Schaltfläche und die zugehörige Schaltfläche "Löschen" enthält. Es funktioniert, aber es ist nicht sehr flexibel, so würde ich im Allgemeinen empfehlen @Joe's Methode als eine bessere Lösung.

Hier ist der entsprechende Code:

Ich habe den gesamten Code in die appDelegate geworfen, um ihn einfach zu halten. Ich empfehle das im wirklichen Leben nicht.

AppDelegate.m:

@implementation AppDelegate

@synthesize window = _window;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

    self.window.backgroundColor = [UIColor whiteColor];

    UIButton *toggleDeleteButtons = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [toggleDeleteButtons setFrame:CGRectMake(20, 45, 280, 45)];
    [toggleDeleteButtons setTitle:@"Toggle Delete" forState:UIControlStateNormal];
    [toggleDeleteButtons addTarget:self action:@selector(toggleDeleteButtonAction) forControlEvents:UIControlEventTouchUpInside];
    [[self window] addSubview:toggleDeleteButtons];

    ButtonWrapper *myButtonWrapper = [[ButtonWrapper alloc] init];
    [[myButtonWrapper button] setFrame:CGRectMake(20, 100, 200, 45)];
    [[myButtonWrapper button] setTitle:@"This is my button" forState:UIControlStateNormal];
    [[myButtonWrapper deleteButton] addTarget:self action:@selector(buttonDeleteRequested:) forControlEvents:UIControlEventTouchUpInside];
    [[myButtonWrapper deleteButton] setTag:0];
    [[self window] addSubview:[myButtonWrapper button]];
    buttonWrapper1 = myButtonWrapper;

    // Added instance called anotherButtonWrapper with tag 1, as above

    // Added instance called stillAnotherButtonWrapper with tag 2, as above

    [self.window makeKeyAndVisible];
    return YES;
}

- (void)toggleDeleteButtonAction {
    static BOOL deleteButtonsShown;

    [buttonWrapper1 showDeleteButton:!deleteButtonsShown];
    [buttonWrapper2 showDeleteButton:!deleteButtonsShown];
    [buttonWrapper3 showDeleteButton:!deleteButtonsShown];
    deleteButtonsShown = !deleteButtonsShown;
}

- (void)buttonDeleteRequested:(UIButton *)deleteButton {
    // delete the specified button here
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Delete" message:[NSString stringWithFormat:@"Delete was pressed on button %i",[deleteButton tag]]delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
    [alert show];
}

ButtonWrapper.m:

@implementation ButtonWrapper

@synthesize button;
@synthesize deleteButton;

- (ButtonWrapper *)init {
    ButtonWrapper *newWrapper = [ButtonWrapper alloc];

    UIButton *myButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [myButton setFrame:CGRectZero];

    UIButton *myDeleteButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [myDeleteButton setFrame:CGRectMake(0, 0, 100, 40)];
    [myDeleteButton setTitle:@"Delete" forState:UIControlStateNormal];
    [myDeleteButton setHidden:TRUE];
    [myButton addSubview:myDeleteButton];

    [newWrapper setButton:myButton];
    [newWrapper setDeleteButton:myDeleteButton];

    return newWrapper;
}

- (void)showDeleteButton:(BOOL)showButton {
    if (showButton) {
        [[self deleteButton] setHidden:FALSE];
        [[self deleteButton] setEnabled:TRUE];    }
    else {
        [[self deleteButton] setHidden:TRUE];
        [[self deleteButton] setEnabled:FALSE];
    }
}
@end

Bei dieser Lösung musste ich nicht alle UI-Eigenschaften implementieren, aber es war zusätzliche Arbeit erforderlich, um die eingebetteten Delegierten einzubinden, was mühsam ist. Möglicherweise gibt es eine Möglichkeit, die Delegaten in den Wrapper bei der Initialisierung übergeben, aber ich konnte nicht machen es funktionieren.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X