2015-04-17 2 views
1

Я хочу создать пользовательский вид, похожий на контакты в iPhone. Доступно ли учебное пособие для создания пользовательского представления, аналогичного ABPeoplePickerNavigationController?Необходимо создать пользовательское представление, подобное ABPeoplePickerNavigationController

Обратите внимание, что я не хочу открывать контроллер выбора людей по умолчанию, предоставляемый инфраструктурой AddressBookUI. Кроме того, я хочу привязать этот контроллер навигации к своему основному виду.

Для справки, что я точно хочу, вы можете сослаться на вкладку контактов Whatsapp на устройстве iOS.

EDIT: У меня уже есть список контактов и отображается имя и фамилия человека в виде таблицы. Теперь я хочу создать индекс для алфавитов из A-Z и при нажатии этого индекса, представление таблицы должно прокручиваться до этих контактов. Также, как я могу реализовать функции поиска, чтобы найти пользователя по его/ее имени или фамилии?

+0

Я добавил ссылку на хороший учебник по индексу, который я последовал некоторое время назад, проверить мою последнюю строку в своем ответе –

+0

Я уже упоминал эту ссылку, о которой вы упоминали, но я не понимаю, как динамически получать данные? –

ответ

3

У меня есть одно и то же в приложение, которое я сейчас создаю, и мы также получили вдохновение от таких приложений, как Whatsapp, когда дело доходило до контактов.

Я использовал простой табличный вид с пользовательскими ячейками для визуальных изображений с простым именем &.

Мой процесс был следующим:

  • Создать contact объект в CoreData (или другой постоянный способ хранения данных)
  • Через ABAddressbook рамки вы можете просматривать все ваши контакты и трансформировать их в ваши новые контактные объекты. Содержите ссылку на свой ABPerson в своем объекте Contact, это позволит вам найти и обновить ваши контакты позже, используя ссылки. Если вы этого не сделаете, вам придется просматривать все ваши ABPersons каждый раз, когда вы хотите обновлять свои контакты. Вы можете использовать ABPersons напрямую, но это было бы очень больно для кода.

  • После того, как вы извлекли все свои контакты, сохраните свой контекст, если используете основные данные, или сохраните их в .sqlite.

  • Затем вы можете просто извлечь их в виде массива контактов и отобразить их в пользовательской ячейке по вашему выбору.

This appcoda tutorial - достойная пользовательская ячейка для учебника по табурету. Вы можете найти еще тысячу, просто используя googling «tableview custom cell ios» и найдя разные вещи, которые вам могут понравиться. В конце концов, у вас будет только ячейка с меткой и рисунком, вы МОЖЕТЕ использовать простой UITableViewCell, который я использовал для другого вида таблицы типа «контакт».

Сохраните этот список контактов в актуальном состоянии (получите правильные номера, изображения, имена и т. Д.) И убедитесь, что они существуют до обновления, проверки, был ли контакт удален, добавлен и т. Д.Все, что нужно сделать, чтобы ваш список был точным, и это довольно длительный/раздражающий процесс.

Я мог бы поделиться своим классом контактов, но он содержит много ненужного кода для вас, что может вас смутить, потому что: - Я также проверяю, являются ли эти контакты уже пользователями моего приложения, чтобы переместить их в определенные разделы моего tableview - Я разделил таблицу на 27 разделов (пользователи, затем буквы алфавита).

Также я остановлюсь на этом последнем совете по программированию: было бы неплохо записать сначала именно то, что вам нужно и что вам нужно, получить все возможности на бумаге и т. Д. Я столкнулся с множеством простых проблем, и мне потребовалось некоторое время для решения, потому что я не планировал должным образом или потому, что он был скрыт.

Например:

  • Некоторые из ваших контактов не имеют имен, вообще.
  • Некоторые из ваших контактов имеют имя в поле «Название» (где вы пишете доктор, или господин)
  • Некоторые из ваших контактов не имеют телефонные номера (если вы используете номера телефонов в качестве идентификаторов)
  • некоторые из ваших контактов имеют международное форматирование и некоторые из них не (+32 46556555 или 46556555 0032)
  • некоторые из ваших контактов есть фотографии, сделанные с камерой, некоторые другие из Gmail, которые имеют различные форматы
  • Вы можете иметь повторяющиеся контакты (одно и то же имя, все равно) из-за плохой синхронизации с пользователем
  • Вам необходимо убедитесь, что первое имя/фамилия находится в правильном разделе, кодировка с учетом регистра может вызвать проблемы
  • Вам необходимо найти решение для контакта, начинающегося со смайликов или не буквенно-цифровых символов
  • Ваши пользователи захотят получить индексный список на стороне
  • Конечно, вам нужно добавить панель поиска, потому что у некоторых людей более 1000 контактов.
  • Много еще впереди, я гарантирую это.

Поскольку это очень специфично для приложения, я не собираюсь решать все проблемы, которые у меня были, и что я сделал для этого, но вы получаете идею :) Не стесняйтесь задавать какие-либо конкретные вопросы, хотя и я может уже иметь очень конкретное решение, так как мне в значительной степени пришлось копировать контакты whatsapp с нуля, и, черт возьми, я это сделал. (Я фактически получил то же самое, что и анонимность и iOS)

EDIT: Вот некоторые методы извлечения моих методов ABPerson; ContactDAO в основном взаимодействуют с моей постоянной моделью (CoreData), и я считаю, что их имена достаточно понятны, чтобы вы могли понять, что происходит. Я доволен комментариями и переменными именами, поэтому вы должны прочитать это без особых проблем.

Здесь идет массивный блок кода.

- (NSMutableArray *)getAllRecordsWithPeople:(CFArrayRef)allPeople andAddressBook:(ABAddressBookRef)addressbook{ 
    NSMutableArray *newRecords = [[NSMutableArray alloc]init]; 
    CFIndex nPeople = ABAddressBookGetPersonCount(addressbook); 

    for (int i=0;i < nPeople;i++){ 

     ABRecordRef ref = CFArrayGetValueAtIndex(allPeople,i); 
     ABRecordID refId = ABRecordGetRecordID(ref); 
     NSNumber *recId = [NSNumber numberWithInt:refId]; 
     [newRecords addObject:recId]; 
    } 

    return newRecords; 
} 

- (void)getValidContactsFromAddressBookWithCompletionBlock:(void (^)(NSError *error))completion{ 

    ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, nil); 

    __block BOOL accessGranted = NO; 

    if (&ABAddressBookRequestAccessWithCompletion != NULL) { 
     dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); 

     ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) { 
      accessGranted = granted; 
      dispatch_semaphore_signal(semaphore); 
     }); 

     dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); 
    } 

    if (accessGranted) { 

     NSMutableArray *newRecords  = [[NSMutableArray alloc]init]; 
     NSMutableArray *updatedRecords = [[NSMutableArray alloc]init]; 
     NSMutableArray *unchangedRecords = [[NSMutableArray alloc]init]; 

     CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook); 
     CFIndex nPeople  = ABAddressBookGetPersonCount(addressBook); 

     //Checking the last time we updated 
     NSTimeInterval lastSyncTime; 
     if ([[NSUserDefaults standardUserDefaults]objectForKey:@"LastSyncTime"] == nil){ 
      //This is the first time we update. 
      lastSyncTime = 0; 
     }else{ 
      //Setting the last update in variable 
      lastSyncTime = [[[NSUserDefaults standardUserDefaults]objectForKey:@"LastSyncTime"]doubleValue]; 
     } 

     if (lastSyncTime == 0){ 
      //We have to insert everyone, this is the first time we do this. 
      newRecords = [self getAllRecordsWithPeople:allPeople andAddressBook:addressBook]; 
     }else{ 
      //We have to manually compare everyone to see if something has changed. 

      for (int i=0;i < nPeople;i++) { 

       ABRecordRef ref = CFArrayGetValueAtIndex(allPeople,i); 
       ABRecordID refId = ABRecordGetRecordID(ref); 
       NSNumber *recId = @(refId); 

       CFDateRef recordCreation = ABRecordCopyValue(ref, kABPersonCreationDateProperty); 
       NSDate *recCreDate = (__bridge NSDate *)(recordCreation); 
       NSTimeInterval creDateInterval = [recCreDate timeIntervalSince1970]; 

       if(creDateInterval > lastSyncTime){ 
        //This object was created after my lastSync, this must be a new record 
        [newRecords addObject:recId]; 

       }else{ 

        //Checking the last update of the given record 
        CFDateRef recordUpdate = ABRecordCopyValue(ref, kABPersonModificationDateProperty); 
        NSDate *recUpDate = (__bridge NSDate*)(recordUpdate); 

        if ([recUpDate timeIntervalSince1970] > lastSyncTime){ 
         //The record was somehow updated since last time, we'll update it 
         [updatedRecords addObject:recId]; 

        }else{ 
         //The record wasn't updated nor created, it is therefore unchanged. 
         //We still need to keep it in a separate array to compare deleted contacts 
         [unchangedRecords addObject:recId]; 
        } 
       } 

      } 
      if(allPeople) 
       CFRelease(allPeople); 
     } 

     [self manageNewContacts:newRecords updatedContacts:updatedRecords andUnchangedContacts:unchangedRecords inAddressBook:addressBook andBlock:^(NSError *error) { 
      completion(error); 
     }]; 
    }else{ 
     NSError *error = [NSError errorWithDomain:@"ABAccess access forbidden" code:403 userInfo:nil]; 
     completion(error); 
    } 
} 

- (void)manageNewContacts:(NSMutableArray*)newRecords updatedContacts:(NSMutableArray*)updatedRecords andUnchangedContacts:(NSMutableArray*)unchangedRecords inAddressBook:(ABAddressBookRef)addressbook andBlock:(void (^)(NSError *error))completion{ 

    AppDelegate *app = [UIApplication sharedApplication].delegate; 
    NSManagedObjectContext *context = app.managedObjectContext; 

    //Getting all the CoreData contacts IDs to have something to compare 
    NSArray *coreDataContactsIds = [ContactDAO getAllContactIdsInManagedObjectContext:context]; 

    for (NSDictionary *rec in coreDataContactsIds){ 
     NSNumber *recId = rec[@"record_id"]; 
     if (![unchangedRecords containsObject:recId]){ 
      //The unchanged record doesn't exist locally 

      if (![updatedRecords containsObject:recId]){ 
       //The updated record doesn't exist locally 

       if (![newRecords containsObject:recId]){ 
        //The new record doesn't exist locally 
        //That means the ongoing record has been deleted from the addressbook, 
        //we also have to delete it locally 

        [ContactDAO deleteContactWithID:recId inManagedObjectContext:context]; 

       } 

      } 
     } 

    } 

    for (NSNumber *recId in updatedRecords){ 
     ABRecordID recordID = (ABRecordID)recId.intValue; 
     ABRecordRef person = ABAddressBookGetPersonWithRecordID(addressbook, recordID); 

     NSDictionary *personDict = [self getPersonDictionaryFromABRecordRef:person]; 
     if (personDict){ 
      [ContactDAO updateContactWithFirstName:personDict[@"firstName"] lastName:personDict[@"lastName"] compositeName:personDict[@"compositeName"] picture:personDict[@"picture"] phoneNumbers:personDict[@"phoneNumbers"] recordID:recId inManagedObjectContext:context]; 
     } 
    } 

    for (NSNumber *recId in newRecords){ 
     ABRecordID recordID = (ABRecordID)recId.intValue; 
     ABRecordRef person = ABAddressBookGetPersonWithRecordID(addressbook, recordID); 

     NSDictionary *personDict = [self getPersonDictionaryFromABRecordRef:person]; 
     if (personDict){ 
      [ContactDAO createContactWithFirstName:personDict[@"firstName"] lastName:personDict[@"lastName"] compositeName:personDict[@"compositeName"] picture:personDict[@"picture"] phoneNumbers:personDict[@"phoneNumbers"] recordID:recId inManagedObjectContext:context]; 
     } 

    } 

    NSError *dbError; 
    [context save:&dbError]; 

    NSTimeInterval lastSyncTime = [[NSDate date]timeIntervalSince1970]; 

    [[NSUserDefaults standardUserDefaults]setObject:@(lastSyncTime) forKey:@"LastSyncTime"]; 
    completion(dbError); 
} 


- (NSDictionary*)getPersonDictionaryFromABRecordRef:(ABRecordRef)person{ 

    //Get name 
    NSString * firstName, *lastName; 
    firstName = CFBridgingRelease(ABRecordCopyValue(person, kABPersonFirstNameProperty)); 
    lastName = CFBridgingRelease(ABRecordCopyValue(person, kABPersonLastNameProperty)); 

    firstName = (firstName == nil) ? @"" : firstName; 
    lastName = (lastName == nil) ? @"" : lastName; 
    NSString *compositeName; 

    if ([firstName isEqualToString:@""] && [lastName isEqualToString:@""]){ 
     return nil; 
    } 

    if ([lastName isEqualToString:@""]){ 
     compositeName = [NSString stringWithFormat:@"%@", firstName]; 
    } 
    if ([firstName isEqualToString:@""]){ 
     compositeName = [NSString stringWithFormat:@"%@", lastName]; 
    } 
    if (![lastName isEqualToString:@""] && ![firstName isEqualToString:@""]){ 
     compositeName = [NSString stringWithFormat:@"%@ %@", firstName, lastName]; 
    } 

    //Get picture 
    CFDataRef imageData = ABPersonCopyImageData(person); 
    NSData *data = CFBridgingRelease(imageData); 

    //Get phone numbers 
    NSMutableSet *phoneNumbers = [[NSMutableSet alloc]init]; 

    ABMultiValueRef phones = ABRecordCopyValue(person, kABPersonPhoneProperty); 
    for(CFIndex i = 0; i < ABMultiValueGetCount(phones); i++) { 

     CFStringRef str = ABMultiValueCopyValueAtIndex(phones, i); 
     NSString *num = CFBridgingRelease(str); 
     [phoneNumbers addObject:num]; 
     /*if(str) 
     CFRelease(str);*/ 
    } 

    //Save it in dictionary 
    NSDictionary *personDict = [[NSDictionary alloc]initWithObjectsAndKeys:firstName, @"firstName",lastName , @"lastName",phoneNumbers,@"phoneNumbers", compositeName, @"compositeName", data, @"picture", nil]; 

    //Release everything. 
    if(phones) 
    CFRelease(phones); 

    return personDict; 

} 

Что касается индексов, то this tutorial должно преуспеть.

+0

Спасибо за ваш ответ. У меня есть список контактов из телефонной книги и хранятся в массиве словаря. Теперь вы можете мне помочь Как создать индексы для представления таблиц и реализовать функции поиска, чтобы найти контакты по имени или фамилии? –

+0

это две совершенно разные вещи. Я настоятельно рекомендую вам просто google «SearchBar tutorial ios» и следовать первым двум ссылкам и делать то же самое с индексом. Здесь все объяснено с изображениями и всем остальным. Просто ознакомьтесь со всем своим учебным пособием, это займет у вас всего 2 часа, а затем адаптирует код к вашему приложению. В какой-то момент мы не можем просто скопировать все на stackoverflow –

+0

Я пройду эти учебные пособия и еще раз благодарю вас за помощь. Я могу понять, что мы не можем копировать и вставлять все в переполнение стека. Еще раз благодарю вас за помощь. –

0

Посмотрите на это: http://www.appcoda.com/ios-programming-index-list-uitableview/

Методы табличном помочь, чтобы дать желаемый результат:

- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView 

и

- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title 
+0

Спасибо за ваш комментарий и ссылку.Я уже знаю об этих методах, но хочу знать, как я могу создать индекс из списка контактов и реализовать поиск? –