How to make a page indicator for horizontal recyclerview

前端 未结 10 1151
说谎
说谎 2021-01-30 05:32

Any idea how to create a page indicator for recyclerview list ?

10条回答
  •  旧巷少年郎
    2021-01-30 05:52

    I made adjustments to CirclePagerIndicatorDecoration, so it will support RTL (Right-to-Left) languages. It took me a couple of a days, hope it will help someone:

        import android.content.res.Resources;
        import android.graphics.Canvas;
        import android.graphics.Paint;
        import android.graphics.Rect;
        import android.view.View;
        import android.view.animation.AccelerateDecelerateInterpolator;
        import android.view.animation.Interpolator;
        
        import androidx.annotation.ColorInt;
        import androidx.recyclerview.widget.LinearLayoutManager;
        import androidx.recyclerview.widget.RecyclerView;
        import java.util.Locale;
     
        public class CirclePagerIndicatorDecoration extends RecyclerView.ItemDecoration {
            private int colorActive = 0xDE000000;
            private int colorInactive = 0x33000000;
        
            private static final float DP = Resources.getSystem().getDisplayMetrics().density;
        
            /**
             * Height of the space the indicator takes up at the bottom of the view.
             */
            private final int mIndicatorHeight = (int) (DP * 16);
        
            /**
             * Indicator stroke width.
             */
            private final float mIndicatorStrokeWidth = DP * 4;
        
            /**
             * Indicator width.
             */
            private final float mIndicatorItemLength = DP * 4;
            /**
             * Padding between indicators.
             */
            private final float mIndicatorItemPadding = DP * 8;
        
            /**
             * Some more natural animation interpolation
             */
            private final Interpolator mInterpolator = new AccelerateDecelerateInterpolator();
        
            private final Paint mPaint = new Paint();
        
            public CirclePagerIndicatorDecoration(@ColorInt int colorInactive) {
        
                mPaint.setStrokeWidth(mIndicatorStrokeWidth);
                mPaint.setStyle(Paint.Style.STROKE);
                mPaint.setAntiAlias(true);
                colorActive = colorInactive;
            }
        
            @Override
            public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
                super.onDrawOver(c, parent, state);
        
                int itemCount = parent.getAdapter().getItemCount();
        
                // center horizontally, calculate width and subtract half from center
                float totalLength = mIndicatorItemLength * itemCount;
                float paddingBetweenItems = Math.max(0, itemCount - 1) * mIndicatorItemPadding;
                float indicatorTotalWidth = totalLength + paddingBetweenItems;
                float indicatorStartX = (parent.getWidth() - indicatorTotalWidth) / 2F;
        
                // center vertically in the allotted space
                float indicatorPosY = parent.getHeight() - mIndicatorHeight / 2F;
        
                drawInactiveIndicators(c, indicatorStartX, indicatorPosY, itemCount);
        
                // find active page (which should be highlighted)
                LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
                int activePosition;
                if (isRtlLanguage()) {
                    activePosition = layoutManager.findLastVisibleItemPosition();
                } else {
                    activePosition = layoutManager.findFirstVisibleItemPosition();
                }
        
                if (activePosition == RecyclerView.NO_POSITION) {
                    return;
                }
        
                // find offset of active page (if the user is scrolling)
                final View activeChild = layoutManager.findViewByPosition(activePosition);
                int left = activeChild.getLeft();
                int width = activeChild.getWidth();
                int right = activeChild.getRight();
        
                // on swipe the active item will be positioned from [-width, 0]
                // interpolate offset for smooth animation
                float progress = mInterpolator.getInterpolation(left * -1 / (float) width);
        
                if (isRtlLanguage()) {
                    indicatorStartX = (parent.getWidth() + indicatorTotalWidth) / 2F - (mIndicatorItemLength + DP * 4) / 2;
                }
        
        //        float indicatorStartXhl = (parent.getWidth() + indicatorTotalWidth) / 2F - (mIndicatorItemLength + DP * 4) / 2;
                drawHighlights(c, indicatorStartX, indicatorPosY, activePosition, progress);
            }
        
            private void drawInactiveIndicators(Canvas c, float indicatorStartX, float indicatorPosY, int itemCount) {
                mPaint.setColor(colorInactive);
        
                // width of item indicator including padding
                final float itemWidth = mIndicatorItemLength + mIndicatorItemPadding;
        
                float start = indicatorStartX;
                for (int i = 0; i < itemCount; i++) {
        
                    c.drawCircle(start, indicatorPosY, mIndicatorItemLength / 2F, mPaint);
        
                    start += itemWidth;
                }
            }
        
            private void drawHighlights(Canvas c, float indicatorStartX, float indicatorPosY,
                                        int highlightPosition, float progress) {
                mPaint.setColor(colorActive);
        
                // width of item indicator including padding
                final float itemWidth = mIndicatorItemLength + mIndicatorItemPadding;
        
                if (progress == 0F) {
                    // no swipe, draw a normal indicator
                    float highlightStart;
                    if (isRtlLanguage()) {
                        highlightStart = indicatorStartX - itemWidth * highlightPosition;
                    } else {
                        highlightStart = indicatorStartX + itemWidth * highlightPosition;
                    }
        
                    c.drawCircle(highlightStart, indicatorPosY, mIndicatorItemLength / 2F, mPaint);
        
                } else {
        
                    float highlightStart;
                    if (isRtlLanguage()) {
                        highlightStart = indicatorStartX - itemWidth * highlightPosition;
                    } else {
                        highlightStart = indicatorStartX + itemWidth * highlightPosition;
                    }
        
                    float partialLength = mIndicatorItemLength * progress + mIndicatorItemPadding * progress;
        
                    c.drawCircle(highlightStart + partialLength, indicatorPosY, mIndicatorItemLength / 2F, mPaint);
                }
            }
        
            @Override
            public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
                super.getItemOffsets(outRect, view, parent, state);
                outRect.bottom = mIndicatorHeight;
            }
        }
    
    
    //The method that checks if it's RTL language:
        private boolean isRtlLanguage() {
                String deviceLanguage = Locale.getDefault().getLanguage();
                return (deviceLanguage.contains("iw") || deviceLanguage.contains("ar")); //You can change here to your specific language
            }
    

提交回复
热议问题