Android: implement slider style gallery

This commit is contained in:
王劲鹏 2023-06-13 15:11:48 +08:00 committed by osborn
parent 1d7001e01a
commit bab16ddf27
3 changed files with 154 additions and 8 deletions

View File

@ -20,16 +20,18 @@ import android.util.SparseArray;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.github.pengfeizhou.jscore.JSArray; import com.github.pengfeizhou.jscore.JSArray;
import com.github.pengfeizhou.jscore.JSDecoder; import com.github.pengfeizhou.jscore.JSDecoder;
import com.github.pengfeizhou.jscore.JSNull; import com.github.pengfeizhou.jscore.JSNull;
import com.github.pengfeizhou.jscore.JSObject; import com.github.pengfeizhou.jscore.JSObject;
import com.github.pengfeizhou.jscore.JSValue; import com.github.pengfeizhou.jscore.JSValue;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import pub.doric.async.AsyncResult; import pub.doric.async.AsyncResult;
import pub.doric.shader.ViewNode; import pub.doric.shader.ViewNode;
import pub.doric.utils.DoricUtils;
/** /**
* @Description: pub.doric.shader.slider * @Description: pub.doric.shader.slider
@ -46,6 +48,8 @@ class SlideAdapter extends RecyclerView.Adapter<SlideAdapter.DoricViewHolder> {
String renderPageFuncId; String renderPageFuncId;
boolean loop; boolean loop;
float itemWidth;
SlideAdapter(SliderNode sliderNode) { SlideAdapter(SliderNode sliderNode) {
this.sliderNode = sliderNode; this.sliderNode = sliderNode;
} }
@ -71,6 +75,10 @@ class SlideAdapter extends RecyclerView.Adapter<SlideAdapter.DoricViewHolder> {
} catch (Exception e) { } catch (Exception e) {
sliderNode.getDoricContext().getDriver().getRegistry().onException(sliderNode.getDoricContext(), e); sliderNode.getDoricContext().getDriver().getRegistry().onException(sliderNode.getDoricContext(), e);
} }
if (sliderNode.slideStyle.equals("gallery")) {
holder.itemView.getLayoutParams().width = DoricUtils.dp2px(this.itemWidth);
}
} }
@Override @Override
@ -149,6 +157,10 @@ class SlideAdapter extends RecyclerView.Adapter<SlideAdapter.DoricViewHolder> {
} }
} }
void setItemWidth(float itemWidth) {
this.itemWidth = itemWidth;
}
static class DoricViewHolder extends RecyclerView.ViewHolder { static class DoricViewHolder extends RecyclerView.ViewHolder {
SlideItemNode slideItemNode; SlideItemNode slideItemNode;

View File

@ -0,0 +1,97 @@
package pub.doric.shader.slider;
import android.content.Context;
import android.view.View;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import pub.doric.utils.DoricUtils;
public class SliderLayoutManager extends LinearLayoutManager {
private boolean enableGallery;
private float minScale = 1f;
private float itemWidth = 0;
private float minAlpha = 1f;
public SliderLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
@Override
public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
if (enableGallery) {
handleHorizontalView();
}
return super.scrollHorizontallyBy(dx, recycler, state);
}
@Override
public void onLayoutCompleted(RecyclerView.State state) {
super.onLayoutCompleted(state);
//scroll won't be called when first layout completed, so need to handle view at first time
if (enableGallery) {
handleView();
}
}
public void setEnableGallery(boolean enableGallery) {
this.enableGallery = enableGallery;
}
public void setItemWidth(float itemWidth) {
this.itemWidth = itemWidth;
}
public void setMinScale(float minScale) {
this.minScale = minScale;
}
public void setMinAlpha(float minAlpha) {
this.minAlpha = minAlpha;
}
private void handleView() {
if (getOrientation() == LinearLayoutManager.HORIZONTAL) {
handleHorizontalView();
}
}
private void handleHorizontalView() {
float centerViewLeft = (float) (getWidth() - DoricUtils.dp2px(this.itemWidth)) / 2;//the left when the view is centered
float moveX = DoricUtils.dp2px(this.itemWidth);//movement x from one item to another
calculateScale(centerViewLeft, moveX);
}
private void calculateScale(float centerViewLeft, float moveDistance) {
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
assert child != null;
int left = child.getLeft();
if (getOrientation() == LinearLayoutManager.VERTICAL) {
left = child.getTop();
}
float factor = (left - centerViewLeft) / moveDistance;
factor = Math.max(-1f, factor);
factor = Math.min(1f, factor);
if (factor > 0) {
// right view to center
scaleAndAlpha(child, 1f - factor * (1 - minScale), 1 - factor * (1 - minAlpha));
} else {
// left view to center
scaleAndAlpha(child, 1f + factor * (1 - minScale), 1 + factor * (1 - minAlpha));
}
}
}
private void scaleAndAlpha(View view, float scale, float alpha) {
view.setPivotX(view.getWidth() / 2f);
view.setPivotY(view.getHeight() / 2f);
view.setScaleX(scale);
view.setScaleY(scale);
view.setAlpha(alpha);
}
}

View File

@ -17,6 +17,7 @@ package pub.doric.shader.slider;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.graphics.Rect;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.View; import android.view.View;
@ -35,6 +36,7 @@ import pub.doric.extension.bridge.DoricPlugin;
import pub.doric.extension.bridge.DoricPromise; import pub.doric.extension.bridge.DoricPromise;
import pub.doric.shader.SuperNode; import pub.doric.shader.SuperNode;
import pub.doric.shader.ViewNode; import pub.doric.shader.ViewNode;
import pub.doric.utils.DoricUtils;
/** /**
* @Description: pub.doric.shader.slider * @Description: pub.doric.shader.slider
@ -50,9 +52,10 @@ public class SliderNode extends SuperNode<RecyclerView> {
private boolean loop = false; private boolean loop = false;
private String renderPageFuncId; private String renderPageFuncId;
private boolean scrollable = true; private boolean scrollable = true;
private String slideStyle = null; String slideStyle = null;
private float minScale = 0.618f; private float minScale = 0.618f;
private float maxScale = 1; private float maxScale = 1;
private float galleryItemWidth = -1f;
private int slidePosition; private int slidePosition;
private boolean needSlideToPosition; private boolean needSlideToPosition;
@ -64,10 +67,10 @@ public class SliderNode extends SuperNode<RecyclerView> {
@Override @Override
protected RecyclerView build() { protected RecyclerView build() {
RecyclerView recyclerView = new RecyclerView(getContext()); final RecyclerView recyclerView = new RecyclerView(getContext());
final LinearLayoutManager layoutManager = new LinearLayoutManager(getContext()) { final SliderLayoutManager layoutManager = new SliderLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false) {
@Override @Override
public boolean canScrollHorizontally() { public boolean canScrollHorizontally() {
if (!scrollable) { if (!scrollable) {
@ -88,10 +91,28 @@ public class SliderNode extends SuperNode<RecyclerView> {
} }
}; };
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(layoutManager); recyclerView.setLayoutManager(layoutManager);
final PagerSnapHelper snapHelper = new PagerSnapHelper(); final PagerSnapHelper snapHelper = new PagerSnapHelper();
snapHelper.attachToRecyclerView(recyclerView); snapHelper.attachToRecyclerView(recyclerView);
recyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
if (slideStyle.equals("gallery")) {
int position = parent.getChildAdapterPosition(view);
LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
assert layoutManager != null;
int count = layoutManager.getItemCount();
int interval = (recyclerView.getWidth() - DoricUtils.dp2px(SliderNode.this.galleryItemWidth)) / 2;
if (position == 0) {
outRect.left = interval;
} else if (position == count - 1) {
outRect.right = interval;
}
}
}
});
recyclerView.setAdapter(this.slideAdapter); recyclerView.setAdapter(this.slideAdapter);
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override @Override
@ -255,8 +276,24 @@ public class SliderNode extends SuperNode<RecyclerView> {
this.slideStyle = prop.asString().value(); this.slideStyle = prop.asString().value();
} else if (prop.isObject()) { } else if (prop.isObject()) {
this.slideStyle = prop.asObject().getProperty("type").asString().value(); this.slideStyle = prop.asObject().getProperty("type").asString().value();
if (this.slideStyle.equals("zoomOut")) {
this.maxScale = prop.asObject().getProperty("maxScale").asNumber().toFloat(); this.maxScale = prop.asObject().getProperty("maxScale").asNumber().toFloat();
this.minScale = prop.asObject().getProperty("minScale").asNumber().toFloat(); this.minScale = prop.asObject().getProperty("minScale").asNumber().toFloat();
} else if (this.slideStyle.equals("gallery")) {
float galleryMinScale = prop.asObject().getProperty("minScale").asNumber().toFloat();
float galleryMinAlpha = prop.asObject().getProperty("minAlpha").asNumber().toFloat();
this.galleryItemWidth = prop.asObject().getProperty("itemWidth").asNumber().toFloat();
SliderLayoutManager layoutManager = (SliderLayoutManager) mView.getLayoutManager();
if (layoutManager != null) {
layoutManager.setEnableGallery(true);
layoutManager.setMinScale(galleryMinScale);
layoutManager.setMinAlpha(galleryMinAlpha);
layoutManager.setItemWidth(this.galleryItemWidth);
this.slideAdapter.setItemWidth(this.galleryItemWidth);
}
}
} }
break; break;
case "slidePosition": case "slidePosition":