@@ -315,7 +315,29 @@ private static float[] getStateStepInterpolationPoints(
315
315
private static boolean isFirstFocalItemAtLeftOfContainer (KeylineState state ) {
316
316
float firstFocalItemLeft =
317
317
state .getFirstFocalKeyline ().locOffset - (state .getFirstFocalKeyline ().maskedItemSize / 2F );
318
- return firstFocalItemLeft <= 0F || state .getFirstFocalKeyline () == state .getFirstKeyline ();
318
+ return firstFocalItemLeft >= 0F
319
+ && state .getFirstFocalKeyline () == state .getFirstNonAnchorKeyline ();
320
+ }
321
+
322
+ /**
323
+ * Determines whether or not the first focal item for the given {@code state} is at the right of
324
+ * the carousel container and fully visible.
325
+ *
326
+ * @param carousel the {@link Carousel} associated with this {@link KeylineStateList}.
327
+ * @param state the state to check for right item position
328
+ * @return true if the {@code state}'s first focal item has its right aligned with the right of
329
+ * the {@code carousel} container and is fully visible.
330
+ */
331
+ private static boolean isLastFocalItemVisibleAtRightOfContainer (
332
+ Carousel carousel , KeylineState state ) {
333
+ int containerSize = carousel .getContainerHeight ();
334
+ if (carousel .isHorizontal ()) {
335
+ containerSize = carousel .getContainerWidth ();
336
+ }
337
+ float lastFocalItemRight =
338
+ state .getLastFocalKeyline ().locOffset + (state .getLastFocalKeyline ().maskedItemSize / 2F );
339
+ return lastFocalItemRight <= containerSize
340
+ && state .getLastFocalKeyline () == state .getLastNonAnchorKeyline ();
319
341
}
320
342
321
343
/**
@@ -339,6 +361,7 @@ private static List<KeylineState> getStateStepsStart(
339
361
List <KeylineState > steps = new ArrayList <>();
340
362
steps .add (defaultState );
341
363
int firstNonAnchorKeylineIndex = findFirstNonAnchorKeylineIndex (defaultState );
364
+
342
365
// If the first focal item is already at the left of the container or there are no in bounds
343
366
// keylines, return a list of steps that only includes the default state (there is nowhere to
344
367
// shift).
@@ -348,15 +371,26 @@ private static List<KeylineState> getStateStepsStart(
348
371
}
349
372
350
373
int start = firstNonAnchorKeylineIndex ;
351
- int end = defaultState .getFirstFocalKeylineIndex () - 1 ;
374
+ int end = defaultState .getFirstFocalKeylineIndex ();
352
375
int numberOfSteps = end - start ;
353
- float cutoffs = 0 ;
354
-
376
+ float carouselSize =
377
+ carousel . isHorizontal () ? carousel . getContainerWidth () : carousel . getContainerHeight ();
355
378
float originalStart =
356
379
defaultState .getFirstKeyline ().locOffset
357
380
- (defaultState .getFirstKeyline ().maskedItemSize / 2F );
358
381
359
- for (int i = 0 ; i <= numberOfSteps ; i ++) {
382
+ if (numberOfSteps <= 0 && defaultState .getFirstFocalKeyline ().cutoff > 0 ) {
383
+ // If there are no steps, there still might be a cutoff focal item that we should shift into
384
+ // view. Add a step that shifts all the keylines over to bring the first focal item into full
385
+ // view.
386
+ float cutoffs = defaultState .getFirstFocalKeyline ().cutoff ;
387
+ steps .add (
388
+ shiftKeylinesAndCreateKeylineState (defaultState , originalStart + cutoffs , carouselSize ));
389
+ return steps ;
390
+ }
391
+
392
+ float cutoffs = 0 ;
393
+ for (int i = 0 ; i < numberOfSteps ; i ++) {
360
394
KeylineState prevStepState = steps .get (steps .size () - 1 );
361
395
int itemOrigIndex = start + i ;
362
396
// If this is the first item from the original state, place it at the end of the dest state.
@@ -382,35 +416,12 @@ private static List<KeylineState> getStateStepsStart(
382
416
originalStart + cutoffs ,
383
417
newFirstFocalIndex ,
384
418
newLastFocalIndex ,
385
- carousel .isHorizontal ()
386
- ? carousel .getContainerWidth ()
387
- : carousel .getContainerHeight ());
419
+ carouselSize );
388
420
steps .add (shifted );
389
421
}
390
422
return steps ;
391
423
}
392
424
393
- /**
394
- * Determines whether or not the first focal item for the given {@code state} is at the right of
395
- * the carousel container and fully visible.
396
- *
397
- * @param carousel the {@link Carousel} associated with this {@link KeylineStateList}.
398
- * @param state the state to check for right item position
399
- * @return true if the {@code state}'s first focal item has its right aligned with the right of
400
- * the {@code carousel} container and is fully visible.
401
- */
402
- private static boolean isLastFocalItemVisibleAtRightOfContainer (
403
- Carousel carousel , KeylineState state ) {
404
- int containerSize = carousel .getContainerHeight ();
405
- if (carousel .isHorizontal ()) {
406
- containerSize = carousel .getContainerWidth ();
407
- }
408
- float lastFocalItemRight =
409
- state .getLastFocalKeyline ().locOffset + (state .getLastFocalKeyline ().maskedItemSize / 2F );
410
- return lastFocalItemRight <= containerSize
411
- && state .getLastFocalKeyline () == state .getLastNonAnchorKeyline ();
412
- }
413
-
414
425
/**
415
426
* Generates discreet steps which move the focal range from it's original position until it
416
427
* reaches the right of the carousel container.
@@ -441,35 +452,26 @@ private static List<KeylineState> getStateStepsEnd(
441
452
return steps ;
442
453
}
443
454
455
+ int start = defaultState .getLastFocalKeylineIndex ();
456
+ int end = lastNonAnchorKeylineIndex ;
457
+ int numberOfSteps = end - start ;
444
458
float carouselSize =
445
459
carousel .isHorizontal () ? carousel .getContainerWidth () : carousel .getContainerHeight ();
446
-
447
460
float originalStart =
448
461
defaultState .getFirstKeyline ().locOffset
449
462
- (defaultState .getFirstKeyline ().maskedItemSize / 2F );
450
463
451
- // If we are here, it means that the last keyline is focal, but is cut off
452
- // since it is not visible. If this is the case, we want to add one step where
453
- // the keylines are shifted so that the last keyline is visible.
454
- if (defaultState .getLastFocalKeyline () == defaultState .getLastNonAnchorKeyline ()) {
455
- KeylineState shifted =
456
- moveKeylineAndCreateKeylineState (
457
- defaultState ,
458
- /* keylineSrcIndex= */ defaultState .getLastFocalKeylineIndex (),
459
- /* keylineDstIndex= */ defaultState .getFirstFocalKeylineIndex (),
460
- originalStart - defaultState .getLastFocalKeyline ().cutoff ,
461
- defaultState .getFirstFocalKeylineIndex (),
462
- defaultState .getLastFocalKeylineIndex (),
463
- carouselSize );
464
- steps .add (shifted );
464
+ if (numberOfSteps <= 0 && defaultState .getLastFocalKeyline ().cutoff > 0 ) {
465
+ // If there are no steps, there still might be a cutoff focal item that we should shift into
466
+ // view. Add a step that shifts all the keylines over to bring the last focal item into full
467
+ // view.
468
+ float cutoffs = defaultState .getLastFocalKeyline ().cutoff ;
469
+ steps .add (
470
+ shiftKeylinesAndCreateKeylineState (defaultState , originalStart - cutoffs , carouselSize ));
465
471
return steps ;
466
472
}
467
473
468
- int start = defaultState .getLastFocalKeylineIndex ();
469
- int end = lastNonAnchorKeylineIndex ;
470
- int numberOfSteps = end - start ;
471
474
float cutoffs = 0 ;
472
-
473
475
for (int i = 0 ; i < numberOfSteps ; i ++) {
474
476
KeylineState prevStepState = steps .get (steps .size () - 1 );
475
477
int itemOrigIndex = end - i ;
@@ -503,6 +505,28 @@ private static List<KeylineState> getStateStepsEnd(
503
505
return steps ;
504
506
}
505
507
508
+ /**
509
+ * Creates a new, valid KeylineState that has the same order as {@code state} but with all
510
+ * keylines shifted along the scrolling axis.
511
+ *
512
+ * @param state the state to shift
513
+ * @param startOffset the point along the scrolling axis where keylines should start being added
514
+ * from
515
+ * @param carouselSize the size of the carousel container
516
+ * @return a new {@link KeylineState} with the shifted keylines
517
+ */
518
+ private static KeylineState shiftKeylinesAndCreateKeylineState (
519
+ KeylineState state , float startOffset , float carouselSize ) {
520
+ return moveKeylineAndCreateKeylineState (
521
+ state ,
522
+ 0 ,
523
+ 0 ,
524
+ startOffset ,
525
+ state .getFirstFocalKeylineIndex (),
526
+ state .getLastFocalKeylineIndex (),
527
+ carouselSize );
528
+ }
529
+
506
530
/**
507
531
* Creates a new, valid KeylineState from a list of keylines that have been re-arranged.
508
532
*
0 commit comments