Android: implement slider style gallery
This commit is contained in:
parent
1d7001e01a
commit
bab16ddf27
@ -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;
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
||||||
this.maxScale = prop.asObject().getProperty("maxScale").asNumber().toFloat();
|
if (this.slideStyle.equals("zoomOut")) {
|
||||||
this.minScale = prop.asObject().getProperty("minScale").asNumber().toFloat();
|
this.maxScale = prop.asObject().getProperty("maxScale").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":
|
||||||
|
Reference in New Issue
Block a user