Skip to content
This repository was archived by the owner on Dec 27, 2024. It is now read-only.

Commit a549d36

Browse files
authored
Improvements on Carousel (#32)
* Improvements on Carousel Simplify support, add invisible/gone choice for empty behavior Fix a bug in MotionLayout not applying a ConstraintSet in some situations. * Update Carousel.java
1 parent 8848939 commit a549d36

File tree

11 files changed

+649
-616
lines changed

11 files changed

+649
-616
lines changed

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
projects/CarouselExperiments/.idea/vcs.xml
3+
projects/CarouselExperiments/.idea/misc.xml
4+
projects/CarouselExperiments/.idea/jarRepositories.xml
5+
projects/CarouselExperiments/.idea/gradle.xml
6+
projects/CarouselExperiments/.idea/compiler.xml

constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/helper/widget/Carousel.java

Lines changed: 48 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import android.content.res.TypedArray;
2121
import android.os.Build;
2222
import android.util.AttributeSet;
23+
import android.util.Log;
2324
import android.view.View;
2425

2526
import androidx.annotation.RequiresApi;
@@ -33,26 +34,21 @@
3334

3435
public class Carousel extends MotionHelper {
3536
private static final boolean DEBUG = false;
37+
private static final String TAG = "Carousel";
3638
private Adapter mAdapter = null;
3739
private ArrayList<View> mList = new ArrayList<>();
3840
private int mPreviousIndex = 0;
3941
private int mIndex = 0;
4042
private MotionLayout mMotionLayout;
4143
private int firstViewReference = -1;
42-
private int lastViewReference = -1;
4344

4445
private int backwardTransition = -1;
4546
private int forwardTransition = -1;
46-
private int forwardStartTransition = -1; // optional
47-
private int forwardEndTransition = -1; // optional
48-
private int forwardMinEndTransition = -1; // optional
49-
private int defaultTransition = -1; // optional
50-
private int minEndThreshold = -1;
5147
private int previousState = -1;
5248
private int nextState = -1;
5349
private float dampening = 0.9f;
5450
private int startIndex = 0;
55-
private int endIndex = 0;
51+
private int emptyViewBehavior = INVISIBLE;
5652

5753
public static final int TOUCH_UP_IMMEDIATE_STOP = 1;
5854
public static final int TOUCH_UP_CARRY_ON = 2;
@@ -63,8 +59,7 @@ public class Carousel extends MotionHelper {
6359
public interface Adapter {
6460
int count();
6561
void populate(View view, int index);
66-
67-
void newItem(int mIndex);
62+
void onNewItem(int mIndex);
6863
}
6964

7065
public Carousel(Context context) {
@@ -89,22 +84,12 @@ private void init(Context context, AttributeSet attrs) {
8984
int attr = a.getIndex(i);
9085
if (attr == R.styleable.Carousel_carousel_firstView) {
9186
firstViewReference = a.getResourceId(attr, firstViewReference);
92-
} else if (attr == R.styleable.Carousel_carousel_lastView) {
93-
lastViewReference = a.getResourceId(attr, lastViewReference);
9487
} else if (attr == R.styleable.Carousel_carousel_backwardTransition) {
9588
backwardTransition = a.getResourceId(attr, backwardTransition);
9689
} else if (attr == R.styleable.Carousel_carousel_forwardTransition) {
9790
forwardTransition = a.getResourceId(attr, forwardTransition);
98-
} else if (attr == R.styleable.Carousel_carousel_forwardStartTransition) {
99-
forwardStartTransition = a.getResourceId(attr, forwardStartTransition);
100-
} else if (attr == R.styleable.Carousel_carousel_forwardEndTransition) {
101-
forwardEndTransition = a.getResourceId(attr, forwardEndTransition);
102-
} else if (attr == R.styleable.Carousel_carousel_forwardMinEndTransition) {
103-
forwardMinEndTransition = a.getResourceId(attr, forwardMinEndTransition);
104-
} else if (attr == R.styleable.Carousel_carousel_defaultTransition) {
105-
defaultTransition = a.getResourceId(attr, defaultTransition);
106-
} else if (attr == R.styleable.Carousel_carousel_minEndThreshold) {
107-
minEndThreshold = a.getInteger(attr, minEndThreshold);
91+
} else if (attr == R.styleable.Carousel_carousel_emptyViewsBehavior) {
92+
emptyViewBehavior = a.getInt(attr, emptyViewBehavior);
10893
} else if (attr == R.styleable.Carousel_carousel_previousState) {
10994
previousState = a.getResourceId(attr, previousState);
11095
} else if (attr == R.styleable.Carousel_carousel_nextState) {
@@ -128,7 +113,7 @@ public void refresh() {
128113
for (int i = 0; i < count; i++) {
129114
View view = mList.get(i);
130115
if (mAdapter.count() == 0) {
131-
updateViewVisibility(view, INVISIBLE);
116+
updateViewVisibility(view, emptyViewBehavior);
132117
} else {
133118
updateViewVisibility(view, VISIBLE);
134119
}
@@ -142,28 +127,43 @@ public void onTransitionChange(MotionLayout motionLayout, int startId, int endId
142127
if (DEBUG) {
143128
System.out.println("onTransitionChange from " + startId + " to " + endId + " progress " + progress);
144129
}
130+
mLastStartId = startId;
145131
}
146132

133+
int mLastStartId = -1;
134+
147135
@Override
148136
public void onTransitionCompleted(MotionLayout motionLayout, int currentId) {
137+
System.out.println("on transition completed");
149138
mPreviousIndex = mIndex;
150139
if (currentId == nextState) {
151140
mIndex++;
141+
System.out.println("increment index...");
152142
} else if (currentId == previousState) {
153143
mIndex--;
144+
System.out.println("decrement index...");
154145
}
155146
if (mIndex >= mAdapter.count()) {
156147
mIndex = mAdapter.count() - 1;
148+
System.out.println("index capped... " + mIndex);
157149
}
158150
if (mIndex < 0) {
159151
mIndex = 0;
152+
System.out.println("index zeroed... ");
160153
}
161154

162155
if (mPreviousIndex != mIndex) {
163156
mMotionLayout.post(mUpdateRunnable);
164157
}
165158
}
166159

160+
private void enableAllTransitions(boolean enable) {
161+
ArrayList<MotionScene.Transition> transitions = mMotionLayout.getDefinedTransitions();
162+
for (MotionScene.Transition transition : transitions) {
163+
transition.setEnable(enable);
164+
}
165+
}
166+
167167
private boolean enableTransition(int transitionID, boolean enable) {
168168
if (transitionID == -1) {
169169
return false;
@@ -187,7 +187,7 @@ private boolean enableTransition(int transitionID, boolean enable) {
187187
public void run() {
188188
mMotionLayout.setProgress(0);
189189
updateItems();
190-
mAdapter.newItem(mIndex);
190+
mAdapter.onNewItem(mIndex);
191191
float velocity = mMotionLayout.getVelocity();
192192
if (touchUpMode == TOUCH_UP_CARRY_ON && velocity > velocityThreshold && mIndex < mAdapter.count() - 1) {
193193
final float v = velocity * dampening;
@@ -225,9 +225,6 @@ protected void onAttachedToWindow() {
225225
if (firstViewReference == id) {
226226
startIndex = i;
227227
}
228-
if (lastViewReference == id) {
229-
endIndex = i;
230-
}
231228
mList.add(view);
232229
}
233230
mMotionLayout = container;
@@ -272,36 +269,15 @@ private boolean updateViewVisibility(int constraintSetId, View view, int visibil
272269
if (constraint == null) {
273270
return false;
274271
}
275-
if (constraint.propertySet.visibility == visibility) {
276-
return false;
277-
}
278-
constraint.propertySet.visibility = visibility;
272+
constraint.propertySet.mVisibilityMode = ConstraintSet.VISIBILITY_MODE_IGNORE;
273+
// if (constraint.propertySet.visibility == visibility) {
274+
// return false;
275+
// }
276+
// constraint.propertySet.visibility = visibility;
279277
view.setVisibility(visibility);
280278
return true;
281279
}
282280

283-
private void updateItemsVisibility() {
284-
if (mAdapter == null) {
285-
return;
286-
}
287-
if (mMotionLayout == null) {
288-
return;
289-
}
290-
final int count = mList.size();
291-
for (int i = 0; i < count; i++) {
292-
// mIndex should map to i == startIndex
293-
View view = mList.get(i);
294-
int index = mIndex + i - startIndex;
295-
if (index < 0) {
296-
updateViewVisibility(view, INVISIBLE);
297-
} else if (index >= mAdapter.count()) {
298-
updateViewVisibility(view, INVISIBLE);
299-
} else {
300-
updateViewVisibility(view, VISIBLE);
301-
}
302-
}
303-
}
304-
305281
private void updateItems() {
306282
if (mAdapter == null) {
307283
return;
@@ -312,96 +288,38 @@ private void updateItems() {
312288
if (DEBUG) {
313289
System.out.println("Update items, index: " + mIndex);
314290
}
315-
final int count = mList.size();
316-
boolean needsToRebuild = false;
317-
for (int i = 0; i < count; i++) {
291+
final int viewCount = mList.size();
292+
for (int i = 0; i < viewCount; i++) {
318293
// mIndex should map to i == startIndex
319294
View view = mList.get(i);
320295
int index = mIndex + i - startIndex;
321296
if (index < 0) {
322-
if (forwardEndTransition == -1) {
323-
// no custom start transition, so let's make those views invisible
324-
needsToRebuild |= updateViewVisibility(view, INVISIBLE);
325-
}
297+
updateViewVisibility(view, emptyViewBehavior);
326298
} else if (index >= mAdapter.count()) {
327-
if (forwardEndTransition == -1) {
328-
// no custom end transition, so let's make those views invisible
329-
needsToRebuild |= updateViewVisibility(view, INVISIBLE);
330-
}
299+
updateViewVisibility(view, emptyViewBehavior);
331300
} else {
332-
if (forwardStartTransition == -1 || forwardEndTransition == -1) {
333-
// if we don't have a start/end transitions, we might have modified the
334-
// visibility of the views, so let's make sure they are visible
335-
needsToRebuild |= updateViewVisibility(view, VISIBLE);
336-
}
301+
updateViewVisibility(view, VISIBLE);
337302
mAdapter.populate(view, index);
338303
}
339304
}
340305

341-
if (backwardTransition != -1 && forwardTransition != -1) {
342-
if (mAdapter.count() > 1) {
343-
if (mIndex == 0) {
344-
needsToRebuild |= enableTransition(backwardTransition, false);
345-
if (forwardStartTransition != -1) {
346-
needsToRebuild |= enableTransition(forwardTransition, false);
347-
needsToRebuild |= enableTransition(forwardStartTransition, true);
348-
mMotionLayout.setTransition(forwardStartTransition);
349-
} else {
350-
mMotionLayout.setTransition(forwardTransition);
351-
}
352-
} else {
353-
needsToRebuild |= enableTransition(backwardTransition, true);
354-
}
355-
}
356-
357-
if (mAdapter.count() == 0) {
358-
for (int i = 0; i < count; i++) {
359-
// mIndex should map to i == startIndex
360-
View view = mList.get(i);
361-
// needsToRebuild |= updateViewVisibility(view, INVISIBLE);
362-
}
363-
} else if (mAdapter.count() == 1 && defaultTransition != -1) {
364-
enableTransition(defaultTransition, true);
365-
mMotionLayout.setTransition(defaultTransition);
366-
mMotionLayout.setProgress(0);
367-
} else if (mAdapter.count() > 1) {
368-
if (mIndex == mAdapter.count() - 1) {
369-
needsToRebuild |= enableTransition(forwardTransition, false);
370-
if (forwardEndTransition != -1) {
371-
needsToRebuild |= enableTransition(forwardEndTransition, false);
372-
}
373-
mMotionLayout.setTransition(backwardTransition);
374-
} else {
375-
int lastVisibleIndex = Math.max(0, mAdapter.count() - (mList.size() - endIndex) - 1);
376-
if (DEBUG) {
377-
System.out.println("### index " + mIndex + " endIndex: " + endIndex + " last index is " + lastVisibleIndex + " count " + mAdapter.count());
378-
}
379-
if (mIndex == lastVisibleIndex && forwardEndTransition != -1) {
380-
if (mIndex == 0) {
381-
if (forwardMinEndTransition != -1 && mAdapter.count() < minEndThreshold) {
382-
needsToRebuild |= enableTransition(forwardTransition, false);
383-
needsToRebuild |= enableTransition(forwardStartTransition, false);
384-
needsToRebuild |= enableTransition(forwardMinEndTransition, true);
385-
mMotionLayout.setTransition(forwardMinEndTransition);
386-
} else {
387-
needsToRebuild |= enableTransition(forwardTransition, false);
388-
needsToRebuild |= enableTransition(forwardStartTransition, true);
389-
mMotionLayout.setTransition(forwardStartTransition);
390-
}
391-
} else {
392-
needsToRebuild |= enableTransition(forwardTransition, false);
393-
needsToRebuild |= enableTransition(forwardEndTransition, true);
394-
mMotionLayout.setTransition(forwardEndTransition);
395-
}
396-
} else {
397-
needsToRebuild |= enableTransition(forwardTransition, true);
398-
}
399-
}
400-
}
306+
if (backwardTransition == -1 || forwardTransition == -1) {
307+
Log.w(TAG, "No backward or forward transitions defined for Carousel!");
308+
return;
401309
}
402310

403-
if (needsToRebuild) {
404-
mMotionLayout.rebuildScene();
311+
final int count = mAdapter.count();
312+
if (mIndex == 0) {
313+
enableTransition(backwardTransition, false);
314+
} else {
315+
enableTransition(backwardTransition, true);
316+
mMotionLayout.setTransition(backwardTransition);
317+
}
318+
if (mIndex == count - 1) {
319+
enableTransition(forwardTransition, false);
320+
} else {
321+
enableTransition(forwardTransition, true);
322+
mMotionLayout.setTransition(forwardTransition);
405323
}
406324
}
407325

constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/motion/widget/MotionLayout.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1327,6 +1327,16 @@ public void setTransition(int transitionId) {
13271327
mModel.initFrom(mLayoutWidget, mScene.getConstraintSet(mBeginState), mScene.getConstraintSet(mEndState));
13281328
rebuildScene();
13291329

1330+
if (mTransitionLastPosition != pos) {
1331+
// If the last drawn position isn't the same, we might have to make sure we apply the
1332+
// corresponding constraintset.
1333+
if (pos == 0) {
1334+
mScene.getConstraintSet(mBeginState).applyTo(this);
1335+
} else if (pos == 1) {
1336+
mScene.getConstraintSet(mEndState).applyTo(this);
1337+
}
1338+
}
1339+
13301340
mTransitionLastPosition = Float.isNaN(pos) ? 0 : pos;
13311341

13321342
if (Float.isNaN(pos)) {
@@ -1605,7 +1615,6 @@ public void setProgress(float pos) {
16051615
} else {
16061616
mCurrentState = UNSET;
16071617
setState(TransitionState.MOVING);
1608-
16091618
}
16101619

16111620
if (mScene == null) {

constraintlayout/constraintlayout/src/main/res/values/attrs.xml

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -234,22 +234,20 @@
234234

235235
<declare-styleable name="Carousel">
236236
<attr name="carousel_firstView" format="reference" />
237-
<attr name="carousel_lastView" format="reference" />
238237
<attr name="carousel_previousState" format="reference" />
239238
<attr name="carousel_nextState" format="reference" />
240-
<attr name="carousel_defaultTransition" format="reference" />
241239
<attr name="carousel_forwardTransition" format="reference" />
242240
<attr name="carousel_backwardTransition" format="reference" />
243-
<attr name="carousel_forwardStartTransition" format="reference" />
244-
<attr name="carousel_forwardEndTransition" format="reference" />
245-
<attr name="carousel_forwardMinEndTransition" format="reference" />
246-
<attr name="carousel_minEndThreshold" format="integer" />
247241
<attr name="carousel_touchUp_dampeningFactor" format="float" />
248242
<attr name="carousel_touchUpMode" format="enum">
249243
<enum name="immediateStop" value="1"/>
250244
<enum name="carryVelocity" value="2"/>
251245
</attr>
252246
<attr name="carousel_touchUp_velocityThreshold" format="float"/>
247+
<attr name="carousel_emptyViewsBehavior" format="enum">
248+
<enum name="invisible" value="4"/>
249+
<enum name="gone" value="8" />
250+
</attr>
253251
</declare-styleable>
254252

255253
<!-- =============================== End Carousel =============================== -->

0 commit comments

Comments
 (0)