diff --git a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/helper/widget/Carousel.java b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/helper/widget/Carousel.java index 38a914442..79ddf34ef 100644 --- a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/helper/widget/Carousel.java +++ b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/helper/widget/Carousel.java @@ -36,12 +36,12 @@ public class Carousel extends MotionHelper { private static final boolean DEBUG = false; private static final String TAG = "Carousel"; private Adapter mAdapter = null; - private ArrayList mList = new ArrayList<>(); + private final ArrayList mList = new ArrayList<>(); private int mPreviousIndex = 0; private int mIndex = 0; private MotionLayout mMotionLayout; private int firstViewReference = -1; - + private boolean infiniteCarousel = false; private int backwardTransition = -1; private int forwardTransition = -1; private int previousState = -1; @@ -58,7 +58,9 @@ public class Carousel extends MotionHelper { public interface Adapter { int count(); + void populate(View view, int index); + void onNewItem(int mIndex); } @@ -100,13 +102,17 @@ private void init(Context context, AttributeSet attrs) { touchUpMode = a.getInt(attr, touchUpMode); } else if (attr == R.styleable.Carousel_carousel_touchUp_velocityThreshold) { velocityThreshold = a.getFloat(attr, velocityThreshold); + } else if (attr == R.styleable.Carousel_carousel_infinite) { + infiniteCarousel = a.getBoolean(attr, infiniteCarousel); } } a.recycle(); } } - public void setAdapter(Adapter adapter) { mAdapter = adapter; } + public void setAdapter(Adapter adapter) { + mAdapter = adapter; + } public void refresh() { final int count = mList.size(); @@ -134,22 +140,26 @@ public void onTransitionChange(MotionLayout motionLayout, int startId, int endId @Override public void onTransitionCompleted(MotionLayout motionLayout, int currentId) { - System.out.println("on transition completed"); mPreviousIndex = mIndex; if (currentId == nextState) { mIndex++; - System.out.println("increment index..."); } else if (currentId == previousState) { mIndex--; - System.out.println("decrement index..."); - } - if (mIndex >= mAdapter.count()) { - mIndex = mAdapter.count() - 1; - System.out.println("index capped... " + mIndex); } - if (mIndex < 0) { - mIndex = 0; - System.out.println("index zeroed... "); + if (infiniteCarousel) { + if (mIndex >= mAdapter.count()) { + mIndex = 0; + } + if (mIndex < 0) { + mIndex = mAdapter.count() - 1; + } + } else { + if (mIndex >= mAdapter.count()) { + mIndex = mAdapter.count() - 1; + } + if (mIndex < 0) { + mIndex = 0; + } } if (mPreviousIndex != mIndex) { @@ -244,6 +254,7 @@ protected void onAttachedToWindow() { /** * Update the view visibility on the different constraintsets + * * @param view * @param visibility * @return @@ -285,6 +296,9 @@ private void updateItems() { if (mMotionLayout == null) { return; } + if (mAdapter.count() == 0) { + return; + } if (DEBUG) { System.out.println("Update items, index: " + mIndex); } @@ -293,13 +307,43 @@ private void updateItems() { // mIndex should map to i == startIndex View view = mList.get(i); int index = mIndex + i - startIndex; - if (index < 0) { - updateViewVisibility(view, emptyViewBehavior); - } else if (index >= mAdapter.count()) { - updateViewVisibility(view, emptyViewBehavior); + if (infiniteCarousel) { + if (index < 0) { + if (emptyViewBehavior != View.INVISIBLE) { + updateViewVisibility(view, emptyViewBehavior); + } else { + updateViewVisibility(view, VISIBLE); + } + if (index % mAdapter.count() == 0) { + mAdapter.populate(view, 0); + } else { + mAdapter.populate(view, mAdapter.count() + (index % mAdapter.count())); + } + } else if (index >= mAdapter.count()) { + if (index == mAdapter.count()) { + index = 0; + } else if (index > mAdapter.count()) { + index = index % mAdapter.count(); + } + if (emptyViewBehavior != View.INVISIBLE) { + updateViewVisibility(view, emptyViewBehavior); + } else { + updateViewVisibility(view, VISIBLE); + } + mAdapter.populate(view, index); + } else { + updateViewVisibility(view, VISIBLE); + mAdapter.populate(view, index); + } } else { - updateViewVisibility(view, VISIBLE); - mAdapter.populate(view, index); + if (index < 0) { + updateViewVisibility(view, emptyViewBehavior); + } else if (index >= mAdapter.count()) { + updateViewVisibility(view, emptyViewBehavior); + } else { + updateViewVisibility(view, VISIBLE); + mAdapter.populate(view, index); + } } } @@ -308,6 +352,10 @@ private void updateItems() { return; } + if (infiniteCarousel) { + return; + } + final int count = mAdapter.count(); if (mIndex == 0) { enableTransition(backwardTransition, false); @@ -315,7 +363,7 @@ private void updateItems() { enableTransition(backwardTransition, true); mMotionLayout.setTransition(backwardTransition); } - if (mIndex == count - 1) { + if (mIndex == count - 1) { enableTransition(forwardTransition, false); } else { enableTransition(forwardTransition, true); diff --git a/constraintlayout/constraintlayout/src/main/res/values/attrs.xml b/constraintlayout/constraintlayout/src/main/res/values/attrs.xml index 749e27540..027a37d1d 100644 --- a/constraintlayout/constraintlayout/src/main/res/values/attrs.xml +++ b/constraintlayout/constraintlayout/src/main/res/values/attrs.xml @@ -236,6 +236,7 @@ + diff --git a/projects/CarouselExperiments/app/src/main/AndroidManifest.xml b/projects/CarouselExperiments/app/src/main/AndroidManifest.xml index ef1c5bf1b..6385bcf1c 100644 --- a/projects/CarouselExperiments/app/src/main/AndroidManifest.xml +++ b/projects/CarouselExperiments/app/src/main/AndroidManifest.xml @@ -16,6 +16,7 @@ + \ No newline at end of file diff --git a/projects/CarouselExperiments/app/src/main/java/androidx/constraintlayout/experiments/CarouselHelperActivity.kt b/projects/CarouselExperiments/app/src/main/java/androidx/constraintlayout/experiments/CarouselHelperActivity.kt new file mode 100644 index 000000000..9c3ae8a59 --- /dev/null +++ b/projects/CarouselExperiments/app/src/main/java/androidx/constraintlayout/experiments/CarouselHelperActivity.kt @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package androidx.constraintlayout.experiments + +import android.graphics.Color +import android.os.Bundle +import android.view.View +import androidx.appcompat.app.AppCompatActivity +import androidx.constraintlayout.helper.widget.Carousel +import com.google.android.material.card.MaterialCardView + +class CarouselHelperActivity : AppCompatActivity() { + var colors = intArrayOf( + Color.parseColor("#ffd54f"), + Color.parseColor("#ffca28"), + Color.parseColor("#ffc107"), + Color.parseColor("#ffb300"), + Color.parseColor("#ffa000"), + Color.parseColor("#ff8f00"), + Color.parseColor("#ff6f00"), + Color.parseColor("#c43e00") + ) + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_carousel_helper) + setupCarousel() + } + + + private fun setupCarousel() { + val carousel = findViewById(R.id.carousel) ?: return + val numImages = colors.size + + carousel.setAdapter(object : Carousel.Adapter { + override fun count(): Int { + return numImages + } + + override fun populate(view: View, index: Int) { + if (view is MaterialCardView) { + view.setBackgroundColor(colors[index]) + } + } + + override fun onNewItem(index: Int) { + } + }) + } +} \ No newline at end of file diff --git a/projects/CarouselExperiments/app/src/main/java/androidx/constraintlayout/experiments/Loader.java b/projects/CarouselExperiments/app/src/main/java/androidx/constraintlayout/experiments/Loader.java index 069c9fdd4..a086666da 100644 --- a/projects/CarouselExperiments/app/src/main/java/androidx/constraintlayout/experiments/Loader.java +++ b/projects/CarouselExperiments/app/src/main/java/androidx/constraintlayout/experiments/Loader.java @@ -57,7 +57,7 @@ static MotionLayout findMotionLayout(ViewGroup group) { return null; } - static void normalMenuStartUp(MainActivity mainActivity) { + static void normalMenuStartUp(MainActivity mainActivity, Class[] activitiesDemo) { String[] layouts = getLayouts(s -> s.matches(LAYOUTS_MATCHES)); ScrollView sv = new ScrollView(mainActivity); LinearLayout linearLayout = new LinearLayout(mainActivity); @@ -69,6 +69,16 @@ static void normalMenuStartUp(MainActivity mainActivity) { linearLayout.addView(button); button.setOnClickListener(view -> launch(mainActivity, (String) view.getTag())); } + for (Class aClass : activitiesDemo) { + Button button = new Button(mainActivity); + button.setText("Demo from " + aClass.getSimpleName()); + linearLayout.addView(button); + button.setOnClickListener(v -> { + Intent intent = new Intent(mainActivity, aClass); + mainActivity.startActivity(intent); + }); + } + sv.addView(linearLayout); mainActivity.setContentView(sv); } diff --git a/projects/CarouselExperiments/app/src/main/java/androidx/constraintlayout/experiments/MainActivity.java b/projects/CarouselExperiments/app/src/main/java/androidx/constraintlayout/experiments/MainActivity.java index d6f9c9d07..a00df5da7 100644 --- a/projects/CarouselExperiments/app/src/main/java/androidx/constraintlayout/experiments/MainActivity.java +++ b/projects/CarouselExperiments/app/src/main/java/androidx/constraintlayout/experiments/MainActivity.java @@ -73,6 +73,11 @@ public class MainActivity extends AppCompatActivity { Color.parseColor("#45C0B8"), }; + // Array from Activities with more examples + Class activitiesDemo[] = { + CarouselHelperActivity.class + }; + //////////////////////////////////////////////////////////////// @Override @@ -80,7 +85,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); Bundle extra = getIntent().getExtras(); if (extra == null) { - Loader.normalMenuStartUp(this); + Loader.normalMenuStartUp(this, activitiesDemo); return; } setupActivity(extra); diff --git a/projects/CarouselExperiments/app/src/main/res/layout/activity_carousel_helper.xml b/projects/CarouselExperiments/app/src/main/res/layout/activity_carousel_helper.xml new file mode 100644 index 000000000..ca6023c10 --- /dev/null +++ b/projects/CarouselExperiments/app/src/main/res/layout/activity_carousel_helper.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/projects/CarouselExperiments/app/src/main/res/layout/demo_010_carousel.xml b/projects/CarouselExperiments/app/src/main/res/layout/demo_010_carousel.xml index a2656991f..fd8dd5da4 100644 --- a/projects/CarouselExperiments/app/src/main/res/layout/demo_010_carousel.xml +++ b/projects/CarouselExperiments/app/src/main/res/layout/demo_010_carousel.xml @@ -85,6 +85,7 @@ app:carousel_backwardTransition="@+id/backward" app:carousel_previousState="@+id/previous" app:carousel_nextState="@+id/next" + app:carousel_infinite="true" app:carousel_firstView="@+id/imageView2" app:constraint_referenced_ids="imageView0,imageView1,imageView2,imageView3,imageView4" /> diff --git a/projects/CarouselExperiments/app/src/main/res/layout/demo_030_carousel.xml b/projects/CarouselExperiments/app/src/main/res/layout/demo_030_carousel.xml index 25d9b99c8..fc82e3a75 100644 --- a/projects/CarouselExperiments/app/src/main/res/layout/demo_030_carousel.xml +++ b/projects/CarouselExperiments/app/src/main/res/layout/demo_030_carousel.xml @@ -84,6 +84,7 @@ app:carousel_backwardTransition="@+id/backward" app:carousel_previousState="@+id/previous" app:carousel_nextState="@+id/next" + app:carousel_infinite="true" app:carousel_firstView="@+id/imageView2" app:carousel_touchUpMode="carryVelocity" app:constraint_referenced_ids="imageView0,imageView1,imageView2,imageView3,imageView4" /> diff --git a/projects/CarouselExperiments/app/src/main/res/layout/demo_040_carousel.xml b/projects/CarouselExperiments/app/src/main/res/layout/demo_040_carousel.xml index d7fef44d5..4a8f042c3 100644 --- a/projects/CarouselExperiments/app/src/main/res/layout/demo_040_carousel.xml +++ b/projects/CarouselExperiments/app/src/main/res/layout/demo_040_carousel.xml @@ -64,6 +64,7 @@ app:carousel_backwardTransition="@+id/backward" app:carousel_previousState="@+id/previous" app:carousel_nextState="@+id/next" + app:carousel_infinite="true" app:carousel_firstView="@+id/imageView2" app:constraint_referenced_ids="imageView1,imageView2,imageView3,imageView4" /> diff --git a/projects/CarouselExperiments/app/src/main/res/xml/activity_carousel_helper_scene.xml b/projects/CarouselExperiments/app/src/main/res/xml/activity_carousel_helper_scene.xml new file mode 100644 index 000000000..1cf9480df --- /dev/null +++ b/projects/CarouselExperiments/app/src/main/res/xml/activity_carousel_helper_scene.xml @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file