ã€ã³ãã
ç§ã¯ãïŒãã·ã¢ã«ïŒæãè¿ãå€åœã®å°æ¹ã®åœã®å°æ¹éœåžã§ioséçºè ãšããŠåããŠããŸãã çŽ1幎ååãåœã¯ç§ã«åœŒå¥³ã«äœããè² ãããããšã決ããŸãããç¹ã«ãç§ã¯èªåã®äººçã«1幎ãæè¡ã®
è¡£è£ ããã¬ãŒãã³ã°å Žããã£ãŒã¿ãŒãªã©ã®é åçãªãã®ãæ±ã£ãåŸãç§ã¯å®¶ã«æ»ããåã³åãå§ããŸããããã¡ããã顧客ããã¶ã€ããŒããpinterest boardããã€ãŸãUICollectionViewèªäœãšåŒãã§ãã圢åŒã§ããŒã¿ã衚瀺ããå¿ èŠããããããžã§ã¯ãããªããåŸ ãããŸããã§ããã
ãããžã§ã¯ã
ãã®ãããžã§ã¯ãã¯ã骚oneåéå®äŒç€Ÿã®iPadãªãŒã¯ã·ã§ã³ã«ã¿ãã°ã®ãããªãã®ã§ãã ããã§ã®åœŒãã®èšåã«å¯ŸããŠã圌ããã©ã®ããã«åå¿ãããããããªãã®ã§ããªã³ã¯ããã¶ã€ã³ã¬ã€ã¢ãŠãããŸãã¯å®éã®ã¹ã¯ãªãŒã³ã·ã§ããã¯æäŸããŸããã
ã¢ããªã±ãŒã·ã§ã³ã¯ãååãšããŠè€éã§ã¯ãããŸããããã¶ã€ã³ã®åã³ãããç§ãå°ãã ãå®ã£ãã®ã¯ãã¡ã€ã³ç»é¢ã®å€èŠ³ã§ãã ããã¯ãæ°Žå¹³ã¹ã¯ããŒã«ã䌎ã3ã€ã®æ°Žå¹³åã«é 眮ããããããã®ç»åã®ã³ã¬ã¯ã·ã§ã³ã§ãããšæ³å®ãããŠããŸããã èŠçŽ ã®é«ããšå¹ ãåºå®ãããäžå€®ã®è¡ïŒç»åã®æ¯çã«å¿ããŠïŒã 1è¡ç®ãš3è¡ç®ã®èŠçŽ ã®é«ãã¯ãå°ããæ¹åã«ãããã«ç°ãªããç Žãããšããžã®ããã«ãªããŸãã ç§ã®ãã©ã€ãªèª¬æãæåã§ååã«ç解ããŠããªãå Žåã¯ãèšäºã®æåŸã«ããã¹ã¯ãªãŒã³ã·ã§ããïŒæçµçµæã®ãµã³ãã«ïŒãèŠãŠãã ããã ãŸãã¯ããã
UICollectionViewFlowLayout
ããã¯æå°éã®åŽåãè²»ãããæåã®è©Šã¿ã§ããã ãããã®èŠçŽ ã«ééããããšã¯äžåºŠããªãã®ã§ãAppleã®ã¯ã©ã¹ã«å¯Ÿããç§ã®åžæã¯éåžžã«åŒ·ãã£ãã ãŸããç§ã¯éåžžãæ°Žå¹³æ¹åã®ãã€ã³ã¿ã¬ã¹ãããŒããã®åºåã«åçŽã«çŠç¹ãåœãŠãŠãç Žãããšããžã§ã¹ã³ã¢ãªã³ã°ããŸããã æ®å¿µãªãããããŒã«ãæ»ãããããšã¯ã§ããŸããã§ããã
ããåçïŒ
å³ïŒ0-éçºè ã¯æ³å®ããUICollectionViewFlowLayoutã¯
ã¹ã¯ãªãŒã³ã·ã§ããã§2ã€ã®ããšãããããŸãã
- æåïŒUICollectionViewFlowLayoutã¯ãæäžè¡ã®èŠçŽ ã®äžå¿ãäžã®èŠçŽ ã®äžå¿ããäžã«ãªãããã«èŠçŽ ãé 眮ããŸãã äžèšã§èšãã°ãããã«ã¯è»¢ãããŸããã
- 2çªç®ïŒäŸãšããŠãç§ã¯ãã·ã¥ãã¬ããã£ãºã ã®åµå§è ã®åäœãèæ¯ã«ãåè¡èžè¡å®¶ã«ãããŸã æžãããŠããªãçµµç»ãæçš¿ããããšã«ããŸãã
RFQuiltLayout
ç§ã®ã°ãŒã°ã«ã¹ãã«ãéåžžã«åŒ±ããã RFQuiltLayoutãç§ã®å Žåã¯å¯äžã®ã¿ãŒã³ããŒãœãªã¥ãŒã·ã§ã³ã§ãã
ãã®ã¯ã©ã¹ã¯ãããã©ã«ãã®ã»ã«ãµã€ãºCGSizeãæ ŒçŽããå€æ°blockPixelsã䜿çšããŸãã ããªã²ãŒãã¡ãœãã
- (CGSize) blockSizeForItemAtIndexPath:(NSIndexPath *)indexPath;
åã»ã«ã®blockPixelsã®ä¹æ°ãè¿ããŸãã ã€ãŸããblockPixels = {100ã100}ãblockSizeForItemAtIndexPath = {2.2ã0.8}ã®å Žåãã»ã«ã®ãµã€ãºã¯{220ã80}ã«ãªããŸãã
ç§ã®æèŠã§ã¯ãããã¯å°ãå¥åŠãªã·ã¹ãã ã§ããblockPixelsã{1ã1}ã«èšå®ããããªã²ãŒãã¡ãœããã§èŠçŽ ã«å¿ èŠãªãµã€ãºãè¿ããŸããããã®å Žåã®é 眮ã¢ã«ãŽãªãºã ã¯15èŠçŽ ã§ãéåžžã«æéãããããé 眮ããã®ã«100èŠçŽ ãå¿ èŠã§ãèšç®èœåã¯iPadãããæ¥æ¿ã§ãã å¿èã®ã¢ã«ãŽãªãºã ãå解ããã®ã«ååãªæéããªãã£ãã®ã§ãéžææ¹æ³ã«ãã£ãŠblockPixelsã®å€{20ã20}ãéžæããŸãããããã«ããã15åã®ã»ã«ã§éåžžã®ããã©ãŒãã³ã¹ãšè¯å¥œãªé 眮粟床ãåŸãããŸããã
åŒãè£ããããšããžãäœæããã«ã¯ãå°ãããªãã¯ã䜿çšããå¿ èŠããããŸãã-å®éãã»ã«ã®ãµã€ãºèªäœã«ã¯è§ŠããŸããã§ãããé 眮ã®æ®µéã§ã»ã«ãã©ã®è¡ã«ããããèŠã€ããããšãã§ããŸããã§ããããåçãã€ã³ã¹ããŒã«ãããšãã«è¡ããã§ãã¯ããæåãšæåŸã®è¡ã®è¡ã®é«ããæžãããŸããåçã ç»åã¯äžäžãããããã«ããªãã³ã°ãããŸããã åçãããªãã³ã°ã®äžã«ããããããããŒãã¬ãŒãã§ãã£ãå Žåã人ã ã¯èžã®å ãšåºã倱ããããããäžåœã®çœ®ç©ã§ãã£ãå Žåããã©ãŽã³ã¯çŽç« ãªãã§è¡šç€ºããããã«ã·ã£çµšæ¯¯ã§ç§ã®æ±ãããã¯ã¯å±±ãåããŸããã ããããã¯ã©ã€ã¢ã³ãã¯æºè¶³ããŸãããã€ãŸããæè¡ä»æ§ããããã«ä¿®æ£ããããŸã§ãç§ãåãã§ããŸããã ã¡ã€ã³ç»é¢ã®åããªèŠçŽ ã®ä»£ããã«ããã¹ãŠã®ãããã衚瀺ãããŠããã¯ãã§ãã ãã¹ãŠ1500ã
ããå€ãã®èžè¡ïŒ
çµµç»ãè±ç¶ããã¹ã€ã®çœ®ç©ããã®ä»ãã¹ãŠã®1500ã®ç»åããå£ããçŸããã§ãã å³ããçå®ã¯ããµãŒãããŒãã£ã®ãœãªã¥ãŒã·ã§ã³ãç§ãæã£ããšããããšã§ã¯ãããŸããã§ããã ããã§ã¯ããã¬ãŒã¹ã¡ã³ããããŒãžã£ãŒãäœæããŸãããã
äºæ³ãããããã«ããã·ã¢èªã§æ å ±ãèŠã€ããããšã¯ã§ããŸããã§ããïŒããŸãæåŸ ããŠããŸããã§ããïŒããäžå¿ èŠã§å°ãªããšãå°ã圹ã«ç«ã€è±èªã®æåž«ã¯ãäœãšãããŠåŸç¹ããŸããã§ããæ€çŽ¢çµæã®æåã®10ããŒãžã çµæãšããŠãç§ã®ããã¥ã¢ã«ã¯ãå®éã«ã¯ã Appleã®ããã¥ã¡ã³ããšäžèšã®RFQuiltLayoutã³ãŒãã§ããïŒãšããã§ãèè ã®Bryce Reddã«æè¬ã®æãè¡šãããïŒã
SKRaggyCollectionViewLayout
ããã«ã¯ã©ã¹ã®æããªååããaã³ããŸãã
æåã«ãããªã²ãŒãã®ãããã³ã«ãå®çŸ©ããŸããã
@protocol SKRaggyCollectionViewLayoutDelegate <UICollectionViewDelegate> - (float)collectionLayout:(SKRaggyCollectionViewLayout*)layout preferredWidthForItemAtIndexPath:(NSIndexPath *)indexPath; @optional - (UIEdgeInsets)collectionLayout:(SKRaggyCollectionViewLayout*)layout edgeInsetsForItemAtIndexPath:(NSIndexPath *)indexPath; @end
ããªã²ãŒãã¯ã»ã«ã®é«ãã«åœ±é¿ãäžããããšãã§ããªããããç¹å®ã®ã»ã«ã§èŠããå¹ ã ãããããŒãžã£ãŒã«æž¡ããŸãã ããŠãUIEdgeInsetsïŒã»ã«ã®å éšããã£ã³ã°ïŒãè¿ãã¡ãœããã¯ããããªãã§ã
ãããŠãã¡ãããè¡æ°ãæ ŒçŽããããããã£ã¯ã3è¡ã ãã§ãªããæ£æ©ã®ããã«æ©ãããšã§ãããã¯ã©ã¹ããŠãããŒãµã«ã«ããããšã§ãïŒ
@property (nonatomic, assign) NSUInteger numberOfRows;
ä»å®è£ ã
Appleã¯ãè£è¶³ãã¥ãŒãè£ é£Ÿãã¥ãŒãªã©ãUICollectionViewã®è¿œå èŠçŽ ã«ç ©ããããããªãå Žåã¯ãå°ãªããšã次ã®ã¡ãœããããªãŒããŒã©ã€ãããå¿ èŠããããšèšã£ãŠããŸãã
- (CGSize)collectionViewContentSize; - (NSArray*)layoutAttributesForElementsInRect:(CGRect)bounds; - (UICollectionViewLayoutAttributes*)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath; - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds;
åŸè ã§ã¯ããã¹ãŠãæ確ã§ã-newBoundsãã³ã¬ã¯ã·ã§ã³ã®çŸåšã®å¢çã«äžèŽããªãå Žåã¯YESãè¿ããŸãã
æåã®ã¡ãœããã¯åŸã§å®è£ ããããããã«æ®ããlayoutAttributesForItemAtIndexPathã¡ãœããã«é²ã¿ãŸãããã ãã®ååããæãããªããã«ãåèŠçŽ ã®UICollectionViewLayoutAttributesãèšç®ããå¿ èŠããããŸãã UICollectionViewLayoutAttributesã¯ã©ã¹ã®ãªããžã§ã¯ãã«ã¯ãã»ã«ã®ããããçš®é¡ã®ãããããããäœæã§ããtransform3Dãå«ãããªããžã§ã¯ãã®å Žæã«é¢ããå€ãã®æ å ±ãå«ãŸããŠããŸããããã®å Žåã¯ãã£ã1ã€ã®ãã¬ãŒã ãå®è¡ã§ããŸãã
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath { UIEdgeInsets insets = UIEdgeInsetsZero; if ([self.delegate respondsToSelector:@selector(collectionLayout:edgeInsetsForItemAtIndexPath:)]) { insets = [self.delegate collectionLayout:self edgeInsetsForItemAtIndexPath:indexPath]; } // Get saved frame and edge insets for given path and create attributes object with them CGRect frame = [self frameForIndexPath:indexPath]; UICollectionViewLayoutAttributes* attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; attributes.frame = UIEdgeInsetsInsetRect(frame, insets); return attributes; }
å®éãèå³æ·±ãããšã¯ãããŸãã-ããªã²ãŒãããUIEdgeInsetsãååŸããŸããããªã²ãŒããæäŸããå ŽåãframeForIndexPathã¡ãœããã䜿çšããŠãã¬ãŒã ãååŸããåä¿¡ããUIEdgeInsetsããã³CGRectã§å±æ§ãäœæããŠè¿ããŸãã ããããframeForIndexPathã¡ãœããã§ã¯ãã·ã£ãŒãããºã ã®äž»èŠéšåã¯ç§ããé ãããŠããŸãã
- (CGRect)frameForIndexPath:(NSIndexPath*)path { // if there is saved frame for given path, return it NSValue *v = [self.framesByIndexPath objectForKey:path]; if (v) return [v CGRectValue]; // Find X-coordinate and a row which are the closest to the collection left corner. A cell for this path should be placed here. int currentRow = 0; float currentX = MAXFLOAT; for (int i = 0; i < self.edgeXPositions.count; i++) { float x = [[self.edgeXPositions objectAtIndex:i] floatValue]; if (x < currentX) { currentRow = i; currentX = x; } } // Calculate cell frame values based on collection height, current row, currentX, the number of rows and delegate's preferredWidthForItemAtIndexPath: value // If variableFrontierHeight is YES this value will be adjusted for the first and last rows float maxH = self.collectionView.frame.size.height; float rowMaxH = maxH / self.numberOfRows; float x = currentX; float y = rowMaxH * currentRow; float w = [self.delegate collectionLayout:self preferredWidthForItemAtIndexPath:path]; float h = self.collectionView.frame.size.height / self.numberOfRows; float newH = h; // Adjust height of the frame if we need raggy style if (self.variableFrontierHeight) { if (currentRow == 0) { float space = arc4random() % self.randomFirstRowVar; if (self.prevWasTallFirst) { space += self.fixedFirstRowVar; } self.prevWasTallFirst = !self.prevWasTallFirst; y += space; newH -= space; } else if (currentRow == self.numberOfRows - 1) { float space = arc4random() % self.randomLastRowVar; if (self.prevWasTallLast) { space += self.fixedLastRowVar; } self.prevWasTallLast = !self.prevWasTallLast; newH -= space; } } // Assure that we have preferred height more than 1 h = h <= 1 ? 1.f : h; // Adjust frame width with new value of height to save cell's right proportions w = w * newH / h; // Save new calculated data ad return [self.edgeXPositions replaceObjectAtIndex:currentRow withObject:[NSNumber numberWithFloat:x + w]]; CGRect currentRect = CGRectMake(x, y, w, newH); NSValue *value = [NSValue valueWithCGRect:currentRect]; [self.indexPathsByFrame setObject:path forKey:value]; [self.framesByIndexPath setObject:value forKey:path]; return currentRect; }
ç§ã®ãã¹ã¿ã³ãŒããšåè±èªã®ã³ã¡ã³ããããŸãæ確ã§ãªãå Žåã¯ãç䌌ã³ãŒããããæ確ã«
ããã«ãã
[以åã«èšç®ãããã¬ãŒã ãindexPathããŒã䜿çšããŠä¿åããNSMutableDictionaryãåç
§ããŸããåå©ã§ããããšãããã£ãå Žåããã以äžã®ããšã¯ãããŸãã]
[èšç®ãé¿ããããªãå ŽåãæåŸã®ãã¬ãŒã ã®å³å¢çãããŒãã«ã®å é ã«æãè¿ãè¡ãèŠã€ããŸã-ããã§ãçŸåšã®èŠçŽ ãé 眮ããå¿ èŠããããŸãïŒåè¡ã®x座æšã¯NSMutableArray edgeXPositionsã«æ ŒçŽãããŸãïŒ]
[ããã§ãX軞ã®è¡ãšäœçœ®ãããã³èŠçŽ ã®ããªã²ãŒããå¿ èŠãšããå¹ ãç¥ã£ãŠããã®ã§ãå·Šäžé ã®äœçœ®ãèšç®ã§ããŸãã ã³ã¬ã¯ã·ã§ã³ã®é«ããšè¡æ°ãããã£ãŠããã®ã§ãåæã«èŠçŽ ã®é«ããèšç®ããŸã]
[æªåé«ããåŒãè£ããããšããžããå¿ èŠã§ãè¡ãæåãŸãã¯æåŸã®å Žåãèšç®ãããé«ãããããã«æžãããŸã]
[é«ãã1æªæºã®å Žåã¯å®å šã«åçããé«ãã®æžå°ã«æ¯äŸããŠå¹ ãçž®å°ããŸã]
[å°æ¥ã®è¿ éãªã¢ã¯ã»ã¹ãšã¡ãœããããã®æ»ãã®ããã«ãååŸããå€ãindexPathsByFrameããã³framesByIndexPathãã£ã¯ã·ã§ããªã«ä¿åããŸã]
[èšç®ãé¿ããããªãå ŽåãæåŸã®ãã¬ãŒã ã®å³å¢çãããŒãã«ã®å é ã«æãè¿ãè¡ãèŠã€ããŸã-ããã§ãçŸåšã®èŠçŽ ãé 眮ããå¿ èŠããããŸãïŒåè¡ã®x座æšã¯NSMutableArray edgeXPositionsã«æ ŒçŽãããŸãïŒ]
[ããã§ãX軞ã®è¡ãšäœçœ®ãããã³èŠçŽ ã®ããªã²ãŒããå¿ èŠãšããå¹ ãç¥ã£ãŠããã®ã§ãå·Šäžé ã®äœçœ®ãèšç®ã§ããŸãã ã³ã¬ã¯ã·ã§ã³ã®é«ããšè¡æ°ãããã£ãŠããã®ã§ãåæã«èŠçŽ ã®é«ããèšç®ããŸã]
[æªåé«ããåŒãè£ããããšããžããå¿ èŠã§ãè¡ãæåãŸãã¯æåŸã®å Žåãèšç®ãããé«ãããããã«æžãããŸã]
[é«ãã1æªæºã®å Žåã¯å®å šã«åçããé«ãã®æžå°ã«æ¯äŸããŠå¹ ãçž®å°ããŸã]
[å°æ¥ã®è¿ éãªã¢ã¯ã»ã¹ãšã¡ãœããããã®æ»ãã®ããã«ãååŸããå€ãindexPathsByFrameããã³framesByIndexPathãã£ã¯ã·ã§ããªã«ä¿åããŸã]
ãšããã§ãinvalidateLayoutã¡ãœããã§ãããã®indexPathsByFrameãframesByIndexPathãwhat-else-is-cachedããã¹ãŠã¯ãªã¢ããããšãå¿ããŠã¯ãªããŸããã åœç¶ã[super invalidateLayout]ãæ¬ èœããŠããŸããã
contentSizeã«æ»ããŸãã æããã«ãæ°Žå¹³ã¹ã¯ããŒã«ã®å Žåã次ã®ããã«ãªããŸãã
- (CGSize)collectionViewContentSize { return CGSizeMake(self.edgeX, self.collectionView.frame.size.height); }
ããã§ãedgeXã¯æãé ãã«ããã»ã«ã®X座æšã§ãã çµå±ã®ãšããããã¹ãŠã®ã»ã«ãã©ã®ããã«é 眮ãããŠãããã¯ãã§ã«ããã£ãŠããŸãã ãŸãã¯ããããªãã ãŸãã¯ããŸã ããã£ãŠããŸã...確ãã«ããã®äžã§[super prepareLayout]ãåŒã³åºãããšãå¿ããã«prepareLayoutã¡ãœãããåå®çŸ©ããåã»ã«ã®ãã¬ãŒã ãèšç®ããå¿ èŠããããŸã
- (void)prepareLayout { [super prepareLayout]; // calculate and save frames for all indexPaths. Unfortunately, we must do it for all cells to know content size of the collection for (int i = 0; i < [self.collectionView.dataSource collectionView:self.collectionView numberOfItemsInSection:0]; i++) { NSIndexPath *path = [NSIndexPath indexPathForItem:i inSection:0]; [self frameForIndexPath:path]; } }
ã¯ããæ°åäžåã®ã»ã«ãããå Žåãã³ã¬ã¯ã·ã§ã³ãæ¥ãã§ããŒãããããšã¯ãããŸããããä»ã«äºçŽ°ãªæ¹æ³ã¯ãããŸããã
æåŸã«ãæåŸã®ã¡ãœããã§ããlayoutAttributesForElementsInRectããªãŒããŒã©ã€ãããŸãã ãã®äžã§ããã®é åã«è©²åœãããã¹ãŠã®èŠçŽ ã®å±æ§ãè¿ãå¿ èŠããããŸãã ã³ã¬ã¯ã·ã§ã³ããã®ãã¬ãŒã ã®ãµã€ãºã«ã¹ã¯ããŒã«ããããã³ã«åŒã³åºãããŸãã ãã®åŸãããã¯ãã¹ãŠãã£ãã·ã¥ãããŠããããã«èŠãããããã¡ãœããã¯contentSize.width / frame.size.widthåã ãåŒã³åºãããŸãã
ãé¡ããšåŒã°ãããã®ã®ç§ã®å®è£ ïŒåèŠçŽ ã®ãã¬ãŒã ã調ã¹ããããããã®é åãšäº€å·®ããå Žåãè¿ãããé åã«è¿œå ããŸãã
- (NSArray*)layoutAttributesForElementsInRect:(CGRect)bounds { if (CGRectEqualToRect(bounds, self.previousLayoutRect)) { return self.previousLayoutAttributes; } [self.previousLayoutAttributes removeAllObjects]; self.previousLayoutRect = bounds; NSArray *allFrames = self.framesByIndexPath.allValues; for (NSValue *frameValue in allFrames) { CGRect rect = [frameValue CGRectValue]; if (CGRectIntersectsRect(rect, bounds)) { [self.previousLayoutAttributes addObject:[self layoutAttributesForItemAtIndexPath:[self.indexPathsByFrame objectForKey:[NSValue valueWithCGRect:rect]]]]; } } return self.previousLayoutAttributes; }
çµµãããã¯ãã§ããããããã§ã¯ãããŸãã
ç·šéãããæçš¿ã®å€æŽãä¿åããåŸãhabrãšã³ãžã³ãé©ãã»ã©æ¯åãããåé€ããããã§ã
ãã¹ãŠãæ£åžžã«æ©èœãããšããäºå®ã«å¯Ÿãã幞çŠæãéãå»ã£ãçŽåŸã«ãç§ã®å éšã®ä»äºäžæ¯è ã¯è©æ±ºãåºããŸããïŒæé©åããããã«ïŒ ããããã¯ãŒã«ããªãã¯ããã匷ãããšãå€æãããã®å ãªãèªå·±ã¯ãèšæ¶ã®è žãããææå°æ©ãªæé©åããšãããã¬ãŒãºãåŸãŠã1äžåã®èŠçŽ ããã£ãŠãiPad 2ã§ã®ãã¹ãã§ã¯é床äœäžãèŠãããªãã£ããšããäºå®ã®èåŸã«é ããŠããã°ããã®éæé©åã延æããããšã«ããŸããã
ããšãã
誰ããèå³ãæã¡ã誰ããæçšã§ãããæ®ãã¯ãã®æçš¿ãèªãã ãã®å¿èãæã£ãŠãããšæããŸãã ãæž èŽããããšãããããŸããã
æåŸã«ãããã€ãã®ãªã³ã¯ïŒ
- ã¢ããã«ã®ã¬ã€ã
- ããã€ãã®ç·ããã®ãã€ã -ç§ã®æèŠã§ã¯ãããŸãã«ããªããããã¯
- ç§ã®githubã³ãŒã
PS圌ãã¯ãã§ã«æåŸã®ãã¿ãã¬ã«ã¯çµµããªããšç§ã«æžããã åãæäœã3åè¡ããŸãããããã·ã³ã°ãªã³ã¯ãæ¿å ¥ããŠç·šéããä¿åããå€æŽãçºçããããšã確èªããããŒãžãéããå床éããŠåªãããããŸãã-ç»åãåã³æ¶ããŸããã ããã«ãåãç¶æ³ã«ã€ãªããã¯ãã®ãªã³ã¯Or right here㯠ããã®æ©èœç矩åãæããã®ããããŸããã ãã©ãã«ã
念ã®ããããã®äžæ£ãªãªã³ã¯ãåã«ããã¹ãã§ããã«æ®ããŸã
habr.habrastorage.org/post_images/0e1/0c7/be4/0e10c7be44690901268d5dfa9e532d0e.png