From ada9c4a8a80eda948692d0cb1d9c301c7d5cffbd Mon Sep 17 00:00:00 2001 From: John Hoford Date: Sat, 5 Nov 2022 12:32:50 -0700 Subject: [PATCH] Detail Expansion example --- .../app/src/main/AndroidManifest.xml | 8 + .../motionrecycle/RecyclerToDetailView.java | 157 ++++++++++++++++++ .../app/src/main/res/drawable/expand_icon.xml | 5 + .../main/res/layout/recycler_to_detail.xml | 35 ++++ .../res/layout/recycler_to_detail_item.xml | 47 ++++++ .../res/xml/recycler_to_detail_item_scene.xml | 60 +++++++ .../main/res/xml/recycler_to_detail_scene.xml | 53 ++++++ 7 files changed, 365 insertions(+) create mode 100644 demoProjects/ExamplesRecyclerView/app/src/main/java/com/example/motionrecycle/RecyclerToDetailView.java create mode 100644 demoProjects/ExamplesRecyclerView/app/src/main/res/drawable/expand_icon.xml create mode 100644 demoProjects/ExamplesRecyclerView/app/src/main/res/layout/recycler_to_detail.xml create mode 100644 demoProjects/ExamplesRecyclerView/app/src/main/res/layout/recycler_to_detail_item.xml create mode 100644 demoProjects/ExamplesRecyclerView/app/src/main/res/xml/recycler_to_detail_item_scene.xml create mode 100644 demoProjects/ExamplesRecyclerView/app/src/main/res/xml/recycler_to_detail_scene.xml diff --git a/demoProjects/ExamplesRecyclerView/app/src/main/AndroidManifest.xml b/demoProjects/ExamplesRecyclerView/app/src/main/AndroidManifest.xml index 8364384c5..04c253717 100644 --- a/demoProjects/ExamplesRecyclerView/app/src/main/AndroidManifest.xml +++ b/demoProjects/ExamplesRecyclerView/app/src/main/AndroidManifest.xml @@ -55,6 +55,13 @@ + + + + + + @@ -68,6 +75,7 @@ android:name="android.app.lib_name" android:value="" /> + \ No newline at end of file diff --git a/demoProjects/ExamplesRecyclerView/app/src/main/java/com/example/motionrecycle/RecyclerToDetailView.java b/demoProjects/ExamplesRecyclerView/app/src/main/java/com/example/motionrecycle/RecyclerToDetailView.java new file mode 100644 index 000000000..d7f311bf8 --- /dev/null +++ b/demoProjects/ExamplesRecyclerView/app/src/main/java/com/example/motionrecycle/RecyclerToDetailView.java @@ -0,0 +1,157 @@ +package com.example.motionrecycle; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Rect; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.constraintlayout.motion.widget.MotionLayout; +import androidx.constraintlayout.utils.widget.ImageFilterButton; +import androidx.constraintlayout.widget.ConstraintSet; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import java.util.Random; + +public class RecyclerToDetailView extends AppCompatActivity { + int[] mColor = new int[200]; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.recycler_to_detail); + RecyclerView recyclerView = findViewById(R.id.recyclerView); + MotionLayout base = findViewById(R.id.base_motionLayout); + Random random = new Random(); + for (int i = 0; i < mColor.length; i++) { + mColor[i] = random.nextInt(0xFFFFFF) | 0xFF000000; + } + recyclerView.setAdapter(new CustomAdapter(recyclerView, mColor, base)); + recyclerView.setLayoutManager(new LinearLayoutManager(this)); + } + + static class ColorBitmap { + private final Paint paint = new Paint(); + private final float[] hsv = new float[3]; + private final Canvas canvas; + private final float y_offset; + private final Rect bounds = new Rect(); + public final Bitmap bitmap; + public int color; + + ColorBitmap() { + bitmap = Bitmap.createBitmap(256, 256, Bitmap.Config.ARGB_8888); + canvas = new Canvas(bitmap); + paint.setTextSize(64); + y_offset = paint.getFontMetrics().descent; + } + + void update(int color) { + this.color = color; + paint.setColor(color); + canvas.drawRoundRect(0, 0, 256, 256, 128, 128, paint); + Color.colorToHSV(color, hsv); + hsv[0] = (hsv[0] + 180) % 360; + hsv[1] = 1 - hsv[1]; + hsv[2] = 1 - hsv[2]; + paint.setColor(Color.HSVToColor(hsv)); + String s = Integer.toHexString(color).substring(2); + paint.getTextBounds(s, 0, 6, bounds); + canvas.drawText(s, (256 - bounds.right) / 2f, 128 + y_offset, paint); + } + } + + // ========================= The RecyclerView adapter ===================== + static class CustomAdapter extends RecyclerView.Adapter { + private final MotionLayout mBaseMotionLayout; + private final int[] mLocalDataSet; + RecyclerView mRecyclerView; + + public CustomAdapter(RecyclerView recyclerView, int[] colors, MotionLayout base) { + mBaseMotionLayout = base; + mRecyclerView = recyclerView; + mLocalDataSet = colors; + } + + @Override + public CustomViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { + LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext()); + View view = inflater.inflate(R.layout.recycler_to_detail_item, viewGroup, false); + + return new CustomViewHolder(view, mBaseMotionLayout); + } + + @Override + public void onBindViewHolder(CustomViewHolder viewHolder, final int position) { + viewHolder.bind(position, mLocalDataSet[position]); + } + + @Override + public int getItemCount() { + return mLocalDataSet.length; + } + } + + // ========================= The View Holder adapter ===================== + public static class CustomViewHolder extends RecyclerView.ViewHolder { + private final ImageFilterButton button; + private final ImageView imageView; + private final MotionLayout mMotionLayout; + private final MotionLayout mBaseMotionLayout; + ColorBitmap colorBitmap = new ColorBitmap(); + private int mPosition = -1; + + public CustomViewHolder(View view, MotionLayout baseMotionLayout) { + super(view); + mBaseMotionLayout = baseMotionLayout; + mMotionLayout = (MotionLayout) view; + button = view.findViewById(R.id.button); + imageView = view.findViewById(R.id.image); + button.setOnClickListener(this::click); + } + + // use CustomViewHolder to bind expand version + private CustomViewHolder(View view, MotionLayout baseMotionLayout, int color) { + super(view); + mBaseMotionLayout = baseMotionLayout; + mMotionLayout = (MotionLayout) view; + button = view.findViewById(R.id.button); + imageView = view.findViewById(R.id.image); + colorBitmap.update(color); + button.setOnClickListener((v) -> mBaseMotionLayout.transitionToStart()); + } + + public void click(View v) { + CustomViewHolder detailed = (CustomViewHolder) mBaseMotionLayout.getTag(R.id.base_motionLayout); + MotionLayout child = mBaseMotionLayout.findViewById(R.id.detail); + if (detailed == null) { + detailed = new CustomViewHolder(child, mBaseMotionLayout, colorBitmap.color); + mBaseMotionLayout.setTag(R.id.base_motionLayout, detailed); + } + int[] pos = new int[2]; + detailed.bind(mPosition, colorBitmap.color); + ConstraintSet cs = mBaseMotionLayout.getConstraintSet(R.id.start); + mBaseMotionLayout.getLocationInWindow(pos); + int x = pos[0], y = pos[1]; + mMotionLayout.getLocationInWindow(pos); + pos[0] -= x; + pos[1] -= y; + cs.setMargin(R.id.detail, ConstraintSet.TOP, pos[1]); + mBaseMotionLayout.updateState(R.id.start, cs); + mBaseMotionLayout.transitionToEnd(); + } + + public void bind(int position, int color) { + mPosition = position; + colorBitmap.update(color); + imageView.setImageBitmap(colorBitmap.bitmap); + } + } +} \ No newline at end of file diff --git a/demoProjects/ExamplesRecyclerView/app/src/main/res/drawable/expand_icon.xml b/demoProjects/ExamplesRecyclerView/app/src/main/res/drawable/expand_icon.xml new file mode 100644 index 000000000..41b88887f --- /dev/null +++ b/demoProjects/ExamplesRecyclerView/app/src/main/res/drawable/expand_icon.xml @@ -0,0 +1,5 @@ + + + diff --git a/demoProjects/ExamplesRecyclerView/app/src/main/res/layout/recycler_to_detail.xml b/demoProjects/ExamplesRecyclerView/app/src/main/res/layout/recycler_to_detail.xml new file mode 100644 index 000000000..79b9d3c4c --- /dev/null +++ b/demoProjects/ExamplesRecyclerView/app/src/main/res/layout/recycler_to_detail.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demoProjects/ExamplesRecyclerView/app/src/main/res/layout/recycler_to_detail_item.xml b/demoProjects/ExamplesRecyclerView/app/src/main/res/layout/recycler_to_detail_item.xml new file mode 100644 index 000000000..1e61aa872 --- /dev/null +++ b/demoProjects/ExamplesRecyclerView/app/src/main/res/layout/recycler_to_detail_item.xml @@ -0,0 +1,47 @@ + + + + + + + + \ No newline at end of file diff --git a/demoProjects/ExamplesRecyclerView/app/src/main/res/xml/recycler_to_detail_item_scene.xml b/demoProjects/ExamplesRecyclerView/app/src/main/res/xml/recycler_to_detail_item_scene.xml new file mode 100644 index 000000000..bbbc2db15 --- /dev/null +++ b/demoProjects/ExamplesRecyclerView/app/src/main/res/xml/recycler_to_detail_item_scene.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demoProjects/ExamplesRecyclerView/app/src/main/res/xml/recycler_to_detail_scene.xml b/demoProjects/ExamplesRecyclerView/app/src/main/res/xml/recycler_to_detail_scene.xml new file mode 100644 index 000000000..7654033bb --- /dev/null +++ b/demoProjects/ExamplesRecyclerView/app/src/main/res/xml/recycler_to_detail_scene.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file