Android: implement slider style gallery
This commit is contained in:
		| @@ -20,16 +20,18 @@ import android.util.SparseArray; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
|  | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.recyclerview.widget.RecyclerView; | ||||
|  | ||||
| import com.github.pengfeizhou.jscore.JSArray; | ||||
| import com.github.pengfeizhou.jscore.JSDecoder; | ||||
| import com.github.pengfeizhou.jscore.JSNull; | ||||
| import com.github.pengfeizhou.jscore.JSObject; | ||||
| import com.github.pengfeizhou.jscore.JSValue; | ||||
|  | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.recyclerview.widget.RecyclerView; | ||||
| import pub.doric.async.AsyncResult; | ||||
| import pub.doric.shader.ViewNode; | ||||
| import pub.doric.utils.DoricUtils; | ||||
|  | ||||
| /** | ||||
|  * @Description: pub.doric.shader.slider | ||||
| @@ -46,6 +48,8 @@ class SlideAdapter extends RecyclerView.Adapter<SlideAdapter.DoricViewHolder> { | ||||
|     String renderPageFuncId; | ||||
|     boolean loop; | ||||
|  | ||||
|     float itemWidth; | ||||
|  | ||||
|     SlideAdapter(SliderNode sliderNode) { | ||||
|         this.sliderNode = sliderNode; | ||||
|     } | ||||
| @@ -71,6 +75,10 @@ class SlideAdapter extends RecyclerView.Adapter<SlideAdapter.DoricViewHolder> { | ||||
|         } catch (Exception e) { | ||||
|             sliderNode.getDoricContext().getDriver().getRegistry().onException(sliderNode.getDoricContext(), e); | ||||
|         } | ||||
|  | ||||
|         if (sliderNode.slideStyle.equals("gallery")) { | ||||
|             holder.itemView.getLayoutParams().width = DoricUtils.dp2px(this.itemWidth); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @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 { | ||||
|         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.content.Context; | ||||
| import android.graphics.Rect; | ||||
| import android.text.TextUtils; | ||||
| import android.view.View; | ||||
|  | ||||
| @@ -35,6 +36,7 @@ import pub.doric.extension.bridge.DoricPlugin; | ||||
| import pub.doric.extension.bridge.DoricPromise; | ||||
| import pub.doric.shader.SuperNode; | ||||
| import pub.doric.shader.ViewNode; | ||||
| import pub.doric.utils.DoricUtils; | ||||
|  | ||||
| /** | ||||
|  * @Description: pub.doric.shader.slider | ||||
| @@ -50,9 +52,10 @@ public class SliderNode extends SuperNode<RecyclerView> { | ||||
|     private boolean loop = false; | ||||
|     private String renderPageFuncId; | ||||
|     private boolean scrollable = true; | ||||
|     private String slideStyle = null; | ||||
|     String slideStyle = null; | ||||
|     private float minScale = 0.618f; | ||||
|     private float maxScale = 1; | ||||
|     private float galleryItemWidth = -1f; | ||||
|  | ||||
|     private int slidePosition; | ||||
|     private boolean needSlideToPosition; | ||||
| @@ -64,10 +67,10 @@ public class SliderNode extends SuperNode<RecyclerView> { | ||||
|  | ||||
|     @Override | ||||
|     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 | ||||
|             public boolean canScrollHorizontally() { | ||||
|                 if (!scrollable) { | ||||
| @@ -88,10 +91,28 @@ public class SliderNode extends SuperNode<RecyclerView> { | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); | ||||
|         recyclerView.setLayoutManager(layoutManager); | ||||
|         final PagerSnapHelper snapHelper = new PagerSnapHelper(); | ||||
|         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.addOnScrollListener(new RecyclerView.OnScrollListener() { | ||||
|             @Override | ||||
| @@ -255,8 +276,24 @@ public class SliderNode extends SuperNode<RecyclerView> { | ||||
|                     this.slideStyle = prop.asString().value(); | ||||
|                 } else if (prop.isObject()) { | ||||
|                     this.slideStyle = prop.asObject().getProperty("type").asString().value(); | ||||
|                     this.maxScale = prop.asObject().getProperty("maxScale").asNumber().toFloat(); | ||||
|                     this.minScale = prop.asObject().getProperty("minScale").asNumber().toFloat(); | ||||
|                     if (this.slideStyle.equals("zoomOut")) { | ||||
|                         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; | ||||
|             case "slidePosition": | ||||
|   | ||||
		Reference in New Issue
	
	Block a user