Skip to content
This repository was archived by the owner on Dec 27, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.example.motionrecycle.RecyclerToDetailView"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".MainActivity"
android:exported="true">
Expand All @@ -68,6 +75,7 @@
android:name="android.app.lib_name"
android:value="" />
</activity>

</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -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<CustomViewHolder> {
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);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M21,11l0,-8l-8,0l3.29,3.29l-10,10l-3.29,-3.29l0,8l8,0l-3.29,-3.29l10,-10z"/>
</vector>
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.motion.widget.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#1E0A1E"
app:layoutDescription="@xml/recycler_to_detail_scene"
android:id="@+id/base_motionLayout"
tools:context=".MainActivity">

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<!-- <FrameLayout-->
<!-- android:id="@+id/frameLayout"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->

<!-- android:visibility="invisible"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toTopOf="parent">-->

<include layout="@layout/recycler_to_detail_item" android:id="@+id/detail" android:layout_width="match_parent"
android:layout_height="100dp" />
<!-- </FrameLayout>-->

</androidx.constraintlayout.motion.widget.MotionLayout>
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.motion.widget.MotionLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="100dp"
android:id="@+id/expand_child"
android:background="#9FF"

app:layoutDescription="@xml/recycler_to_detail_item_scene">
<View
android:id="@+id/backdrop"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="1dp"
android:layout_marginTop="2dp"
android:layout_marginBottom="2dp"
android:layout_marginEnd="1dp"
android:background="#256671"
/>

<ImageView
android:id="@+id/image"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="1:1"
android:layout_marginBottom="4dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="4dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
/>
<androidx.constraintlayout.utils.widget.ImageFilterButton
android:id="@+id/button"
android:layout_width="50dp"
android:layout_height="50dp"
android:src="@drawable/expand_icon"
android:background="#AAA"
app:roundPercent="1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.motion.widget.MotionLayout>
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:motion="http://schemas.android.com/apk/res-auto">

<Transition
motion:constraintSetEnd="@+id/end"
motion:constraintSetStart="@id/start" >
<KeyFrameSet>
<KeyAttribute
android:rotation="45"
motion:framePosition="20"
motion:motionTarget="@+id/button" />
<KeyAttribute
android:rotation="45"
motion:framePosition="80"
motion:motionTarget="@+id/button" />

</KeyFrameSet>
</Transition>

<ConstraintSet android:id="@+id/start">

<ConstraintOverride android:id="@+id/backdrop">
<CustomAttribute
motion:attributeName="backgroundColor"
motion:customColorValue="#727572" />
</ConstraintOverride>
</ConstraintSet>

<ConstraintSet android:id="@+id/end">

<Constraint
android:id="@+id/backdrop"
android:layout_width="match_parent"
android:layout_height="match_parent">
<CustomAttribute
motion:attributeName="backgroundColor"
motion:customColorValue="#040404" />
</Constraint>

<Constraint
android:id="@+id/button"
android:layout_width="50dp"
android:layout_height="50dp"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintHorizontal_bias="0.5"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent" />

<Constraint
android:id="@+id/image"
android:layout_width="0dp"
android:layout_height="0dp"
motion:layout_constraintDimensionRatio="1:1"
motion:layout_constraintEnd_toEndOf="parent"
motion:layout_constraintStart_toStartOf="parent"
motion:layout_constraintTop_toTopOf="parent" />
</ConstraintSet>
</MotionScene>
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<MotionScene
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:motion="http://schemas.android.com/apk/res-auto">

<Transition
motion:constraintSetEnd="@+id/end"
motion:constraintSetStart="@id/start"
motion:duration="2000">
<KeyFrameSet>
<KeyAttribute motion:motionTarget="@+id/detail" android:alpha="1" motion:framePosition="1"/>
<KeyAttribute motion:motionTarget="@+id/detail" motion:motionProgress="0" motion:framePosition="30"/>
</KeyFrameSet>
</Transition>

<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/recyclerView"
motion:layout_constraintEnd_toEndOf="parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintTop_toTopOf="parent"
motion:layout_constraintStart_toStartOf="parent" />
<Constraint
android:id="@+id/detail"
android:layout_width="wrap_content"
android:layout_height="100dp"
android:visibility="invisible"
motion:motionProgress="0"
motion:layout_constraintTop_toTopOf="parent"
motion:layout_constraintStart_toStartOf="parent" />
</ConstraintSet>

<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/recyclerView"
motion:layout_constraintEnd_toEndOf="parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
motion:layout_constraintBottom_toBottomOf="parent"
motion:layout_constraintTop_toTopOf="parent"
motion:layout_constraintStart_toStartOf="parent"
/>
<Constraint
android:id="@+id/detail"
android:layout_width="match_parent"
android:layout_height="match_parent"
motion:motionProgress="1"
motion:layout_constraintTop_toTopOf="parent"
motion:layout_constraintStart_toStartOf="parent" />
</ConstraintSet>
</MotionScene>