无限滚动无限项 [英] Infinite scroll of finite items

查看:60
本文介绍了无限滚动无限项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个GridView物品的尺寸在5x50以内.

I have a GridView that has items inside 5x50.

我需要在所有方向上滚动它们,而不是在到达终点时停下来,而只是从顶部/左侧开始.

I need to scroll them in all directions and instead of stopping when reached the end just start from the top/left.

例如从左向右滚动

滚动之前

1 2 3 4 5
6 7 8 9 10

向右滚动后

5 1 2 3 4
10 6 7 8 9

以及从上到下(或从下到上)

and for top-to-bottom (or bottom-to-top)

滚动到底部之前

1 2 3 4 5
6 7 8 9 10
11 12 13 14 15

滚动后

6 7 8 9 10
11 12 13 14 15
1 2 3 4 5

我尝试使其平滑滚动,就像GridView本机滚动一样.

I try to make it smooth scroll as GridView native scroll.

推荐答案

这里是另一种解决方案,但用画布的方法.

Here is another solution but with a canvas approach.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/constraint_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <nice.fontaine.infinitescroll.CanvasView
        android:id="@+id/canvas_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</android.support.constraint.ConstraintLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        CanvasView canvas = findViewById(R.id.canvas_view);

        String[][] labels = new String[][] {
                {"5", "8", "2"},
                {"4", "7", "1"},
                {"3", "6", "9"}
        };
        int columns = 3;
        int rows = 3;

        canvas.with(labels, columns, rows);
    }
}

CanvasView.java

public class CanvasView extends View {

    private final Panning panning;
    private final GridManager gridManager;
    private Rect bounds;
    private Point current = new Point(0, 0);
    private List<Overlay> overlays;
    public CanvasView(Context context, AttributeSet attrs) {
        super(context, attrs);
        bounds = new Rect();
        panning = new Panning();
        overlays = new ArrayList<>();
        gridManager = new GridManager(this);
        init();
    }

    public void with(String[][] labels, int columns, int rows) {
        gridManager.with(labels, columns, rows);
    }

    private void init() {
        ViewTreeObserver observer = getViewTreeObserver();
        observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {

            @Override
            public void onGlobalLayout() {
                int width = getWidth();
                int height = getHeight();
                bounds.set(0, 0, width, height);
                gridManager.generate(bounds);
                getViewTreeObserver().removeOnGlobalLayoutListener(this);
            }
        });
    }

    @Override
    protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
        super.onSizeChanged(width, height, oldWidth, oldHeight);
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        new Canvas(bitmap);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        bounds.offsetTo(-current.x, -current.y);
        gridManager.generate(bounds);
        canvas.translate(current.x, current.y);
        for (Overlay overlay : overlays) {
            if (overlay.intersects(bounds)) {
                overlay.onDraw(canvas);
            }
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        current = panning.handle(event);
        invalidate();
        return true;
    }

    public void addChild(Overlay overlay) {
        this.overlays.add(overlay);
    }
}

GridManager.java

class GridManager {

    private final CanvasView canvas;
    private int columns;
    private int rows;
    private String[][] labels;
    private final Map<String, Overlay> cache;

    GridManager(CanvasView canvas) {
        this.canvas = canvas;
        cache = new HashMap<>();
    }

    void with(String[][] labels, int columns, int rows) {
        this.columns = columns;
        this.rows = rows;
        this.labels = labels;
    }

    void generate(Rect bounds) {
        if (columns == 0 || rows == 0 || labels == null) return;
        int width = bounds.width();
        int height = bounds.height();

        int overlayWidth = width / columns;
        int overlayHeight = height / rows;

        int minX = mod(floor(bounds.left, overlayWidth), columns);
        int minY = mod(floor(bounds.top, overlayHeight), rows);

        int startX = floorToMod(bounds.left, overlayWidth);
        int startY = floorToMod(bounds.top, overlayHeight);

        for (int j = 0; j <= rows; j++) {
            for (int i = 0; i <= columns; i++) {
                String label = getLabel(minX, minY, i, j);
                int x = startX + i * overlayWidth;
                int y = startY + j * overlayHeight;

                String key = x + "_" + y;
                if (!cache.containsKey(key)) {
                    Overlay overlay = new Overlay(label, x, y, overlayWidth, overlayHeight);
                    cache.put(key, overlay);
                    canvas.addChild(overlay);
                }
            }
        }
    }

    private String getLabel(int minX, int minY, int i, int j) {
        int m = mod(minX + i, columns);
        int n = mod(minY + j, rows);
        return labels[n][m];
    }

    private int floor(double numerator, double denominator) {
        return (int) Math.floor(numerator / denominator);
    }

    private int floorToMod(int value, int modulo) {
        return value - mod(value, modulo);
    }

    private int mod(int value, int modulo) {
        return (value % modulo + modulo) % modulo;
    }
}

Panning.java

class Panning {

    private Point start;
    private Point delta = new Point(0, 0);
    private Point cursor = new Point(0, 0);
    private boolean isFirst;

    Point handle(MotionEvent event) {
        final Point point = new Point((int) event.getX(), (int) event.getY());
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                press();
                break;
            case MotionEvent.ACTION_MOVE:
                drag(point);
                break;
        }
        return new Point(cursor.x + delta.x, cursor.y + delta.y);
    }

    private void press() {
        isFirst = true;
    }

    private void drag(final Point point) {
        if (isFirst) {
            start = point;
            cursor.offset(delta.x, delta.y);
            isFirst = false;
        }
        delta.x = point.x - start.x;
        delta.y = point.y - start.y;
    }
}

Overlay.java

class Overlay {

    private final String text;
    private final int x;
    private final int y;
    private final Paint paint;
    private final Rect bounds;
    private final Rect rect;
    private final Rect textRect;

    Overlay(String text, int x, int y, int width, int height) {
        this.text = text;
        this.bounds = new Rect(x, y, x + width, y + height);
        this.rect = new Rect();
        this.textRect = new Rect();
        paint = new Paint();
        paint.setColor(Color.BLACK);
        setTextSize(text);
        this.x = x + width / 2 - textRect.width() / 2;
        this.y = y + height / 2 + textRect.height() / 2;
    }

    boolean intersects(Rect r) {
        rect.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
        return rect.intersect(r.left, r.top, r.right, r.bottom);
    }

    void onDraw(Canvas canvas) {
        // rectangle
        paint.setStrokeWidth(5);
        paint.setStyle(Paint.Style.STROKE);
        canvas.drawRect(bounds, paint);

        // centered text
        paint.setStrokeWidth(2);
        paint.setStyle(Paint.Style.FILL);
        canvas.drawText(text, x, y, paint);
    }

    private void setTextSize(String text) {
        final float testTextSize = 100f;
        paint.setTextSize(testTextSize);
        paint.getTextBounds(text, 0, text.length(), textRect);
    }
}

这篇关于无限滚动无限项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆