タップして最大3枚の写真を選択できることを除いて、通常のUIImagePickerControllerと同様のカスタムImagePickerを作成しています。タップして最初の写真を選択すると、小さなUIViewトレイが下からスライドし、選択したサムネイルがそこに表示されます。タップして2枚目と3枚目の写真を選択すると、選択した写真トレイに追加されます。ピッカーで同じ写真をタップすると、トレイから削除されます。(コード内の魔法数についてお詫びします。私は今のところまだテスト中です)
3枚の写真を正しく選択した状態でトレイがどのように見えるかを示すために、下にトリミングした写真を添付しました。
http://dl.dropbox.com/u/762437/screen1.jpg
写真が通常の速度でタップされれば、すべてが正常に機能しています。ただし、ユーザーがどういうわけかランダムな方法で写真をすばやくタップすることにした場合、アニメーションとトレイ上の写真の配置が台無しになることがあります。
以下に例を添付しました。以下の例では、実際には2枚の写真しか選択されていませんが、どういうわけか、3枚目の写真はまだ部分的に表示されています。
http://dl.dropbox.com/u/762437/screen2.jpg
ユーザーがいわば「ボタンをマッシュ」することを決定したときに、このような動作をどのように軽減するかがわかりません。
@synchronized(self)を使用して、assetsWasTapped関数の内部をラップするのが良いかもしれないと思いましたが、何もしなかったようです(assetsWasTappedはメインスレッドから呼び出されます)。
トレイの同じ位置に2枚の写真が追加されることがあります。これにより、各サムネイルの配置場所を決定するために使用するNSMutableArrayカウント(selectedPhotos)にタイミングの問題があると思われます。
特定の質問をお詫びしますが、おそらくそれのより一般的なバージョンは、アニメーションと迅速なユーザー入力を処理する方法でしょう。
どんな助けでも大歓迎です。ありがとうございました!
- (void)assetWasTapped:(CustomAsset*)tappedAsset
{
// The asset thumbnail was tapped. Check if the count is < 3 and add to the tray
if([selectedAssets count] < 3)
{
NSMutableDictionary *dataToAdd = [NSMutableDictionary dictionaryWithObjectsAndKeys:
tappedAsset, @"selectedAsset",
[[tappedAsset.asset defaultRepresentation] url], @"selectedAssetURL",
tappedAsset.indexPath, @"selectedAssetIndexPath",
[NSNumber numberWithInt:[tappedAsset tag]], @"selectedAssetTag", nil];
[selectedAssets addObject:dataToAdd];
[self addAssetToSelectedTray:tappedAsset];
}
}
- (void)addAssetToSelectedTray:(CustomAsset*)tappedAsset
{
UIView *existingButton;
int xPos = 30;
CustomAsset *tempCustomAsset = [[[CustomAsset alloc] initWithAsset:tappedAsset.asset] autorelease];
// Switch to deal with 1~3 selected assets
switch ([selectedAssets count])
{
case 1:
tempCustomAsset.frame = CGRectMake(125, 8, 73, 73);
[selectedPhotosTray addSubview:tempCustomAsset];
break;
case 2:
for(existingButton in [selectedPhotosTray subviews])
{
[UIView animateWithDuration:0.1
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
existingButton.frame = CGRectMake(70, 8, 73, 73);
}
completion:^(BOOL completed){
}
];
}
tempCustomAsset.frame = CGRectMake(180, 8, 73, 73);
[selectedPhotosTray addSubview:tempCustomAsset];
break;
case 3:
for(existingButton in [selectedPhotosTray subviews])
{
[UIView animateWithDuration:0.1
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
existingButton.frame = CGRectMake(xPos, 8, 73, 73);
}
completion:^(BOOL completed){
}
];
xPos += 95;
}
tempCustomAsset.frame = CGRectMake(220, 8, 73, 73);
[selectedPhotosTray addSubview:tempCustomAsset];
break;
default:
break;
}
}
- (void)removeAssetFromSelectedTray:(CustomAsset*)tappedAsset
{
// If the asset was removed, remove from the tray
[UIView animateWithDuration:0.2
delay:0.0
options:UIViewAnimationOptionCurveEaseInOut
animations:^{
tappedAsset.transform = CGAffineTransformMakeScale(0.3, 0.3);
tappedAsset.alpha = 0.0;
}
completion:^(BOOL completed){
[tappedAsset removeFromSuperview];
if([selectedAssets count] == 0)
{
[self closeSelectedPhotosTrayWithAnimation:YES];
}
int xPos = 70;
UIButton *existingButton;
switch ([selectedAssets count])
{
case 1:
for(existingButton in [selectedPhotosTray subviews])
{
[UIView animateWithDuration:0.1
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
existingButton.frame = CGRectMake(125, 8, 73, 73);
}
completion:^(BOOL completed){
}
];
}
break;
case 2:
for(existingButton in [selectedPhotosTray subviews])
{
[UIView animateWithDuration:0.1
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
existingButton.frame = CGRectMake(xPos, 8, 73, 73);
}
completion:^(BOOL completed){
}
];
xPos += 110;
}
break;
default:
break;
}
}
];
}