带有colspan和rowSpan的GridView

8
我一直在尝试制作一个带有拖放功能的网格视图,其中一个单元格大小不同。我已经成功地制作了可拖放的网格,并且它可以正常工作。您可以从这里检查代码。

my code output

但我希望它像这样纯粹动态,因为我将会拖放其他内容,它们将自动被替换和调整大小 期望输出


请了解交错网格布局。如果您可以使用回收视图,类似于这个可能会对您有所帮助。 - Iffat Fatima
我的代码具有拖放功能,如果只是UI方面,我有很多选择,例如https://github.com/felipecsl/AsymmetricGridView。 - Furqan
如果您正在推广一篇知识文章,也请在您的问题中提供一个答案。 - user1773603
除了添加“gridview”标签外,还可以将“gridlayout”标签添加到问题中。 - Adriano
请查看此答案:https://dev59.com/r0jSa4cB1Zd3GeqPJOBt#55550477 - Aashish Kumar
谢谢@Aashish,但下面的答案已经满足了我的要求。 - Furqan
2个回答

4

更新了适应单元格调整大小的新代码。

您的问题涉及GridView,但您提供的代码没有提及GridView而是使用了GridLayout,因此我假设GridLayout是正确的布局。

我已经编写了一个演示,使用了一个2x2的瓷砖模拟布局。我修改了您提供的代码以适应2x2的瓷砖。除了添加实现2x2瓷砖的代码外,MainActivity 的唯一其他更改是 calculateNextIndex 方法,它使用了一个不同的计算在(x, y)位置的索引的方法。布局和 LongPressListener 类也是虚构的,因为它们没有被提供。

这是一个演示的视频:

enter image description here

MainActivity.java

public class MainActivity extends AppCompatActivity {

    private static final int ITEMS = 10;
    private GridLayout mGrid;
    private ScrollView mScrollView;
    private ValueAnimator mAnimator;
    private Boolean isScroll = false;
    private GridLayout.Spec m1xSpec = GridLayout.spec(GridLayout.UNDEFINED, 1);
    private GridLayout.Spec m2xSpec = GridLayout.spec(GridLayout.UNDEFINED, 2);
    private int mBaseWidth;
    private int mBaseHeight;
    private int mBaseMargin;

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mScrollView = (ScrollView) findViewById(R.id.scrollView);
        mScrollView.setSmoothScrollingEnabled(true);

        mGrid = (GridLayout) findViewById(R.id.grid);

        mGrid.setOnDragListener(new DragListener());

        final LayoutInflater inflater = LayoutInflater.from(this);

        GridLayout.LayoutParams lp;

        DisplayMetrics displayMetrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
        float dpiToPx = displayMetrics.density;
        View view = inflater.inflate(R.layout.item, mGrid, false);
        lp = (GridLayout.LayoutParams) view.getLayoutParams();
        mBaseWidth = lp.width;
        mBaseHeight = lp.height;
        mBaseMargin = lp.rightMargin;

        for (int i = 0; i < ITEMS; i++) {
            final View itemView = inflater.inflate(R.layout.item, mGrid, false);
            final TextView text = (TextView) itemView.findViewById(R.id.text);
            text.setText(String.valueOf(i + 1));
            itemView.setOnLongClickListener(new LongPressListener());
            lp = (i == 0) ? make2x2LayoutParams(itemView) : make1x1LayoutParams(itemView);
            mGrid.addView(itemView, lp);
        }
    }

    private GridLayout.LayoutParams make2x2LayoutParams(View view) {
        GridLayout.LayoutParams lp = (GridLayout.LayoutParams) view.getLayoutParams();

        lp.width = mBaseWidth * 2 + 2 * mBaseMargin;
        lp.height = mBaseHeight * 2 + 2 * mBaseMargin;
        lp.rowSpec = m2xSpec;
        lp.columnSpec = m2xSpec;
        lp.setMargins(mBaseMargin, mBaseMargin, mBaseMargin, mBaseMargin);
        return lp;
    }

    private GridLayout.LayoutParams make1x1LayoutParams(View view) {
        GridLayout.LayoutParams lp = (GridLayout.LayoutParams) view.getLayoutParams();

        lp.width = mBaseWidth;
        lp.height = mBaseHeight;
        lp.setMargins(mBaseMargin, mBaseMargin, mBaseMargin, mBaseMargin);
        lp.rowSpec = m1xSpec;
        lp.columnSpec = m1xSpec;
        return lp;
    }

    private int mDraggedIndex;

    class DragListener implements View.OnDragListener {
        @Override
        public boolean onDrag(View v, DragEvent event) {
            final View view = (View) event.getLocalState();
            int index = calculateNextIndex(event.getX(), event.getY());
            View child;

            switch (event.getAction()) {
                case DragEvent.ACTION_DRAG_STARTED:
                    mDraggedIndex = index;
                    break;

                case DragEvent.ACTION_DRAG_LOCATION:
                    if (view == v) return true;
                    // get the new list index


                    final Rect rect = new Rect();
                    mScrollView.getHitRect(rect);
                    final int scrollY = mScrollView.getScrollY();

                    if (event.getY() - scrollY > mScrollView.getBottom() - 250) {
                        startScrolling(scrollY, mGrid.getHeight());
                    } else if (event.getY() - scrollY < mScrollView.getTop() + 250) {
                        startScrolling(scrollY, 0);
                    } else {
                        stopScrolling();
                    }

                    child = mGrid.getChildAt(0);
                    if (index == 0) {
                        child.setLayoutParams(make1x1LayoutParams(child));
                        view.setLayoutParams(make2x2LayoutParams(view));
                    } else if (mDraggedIndex == 0) {
                        view.setLayoutParams(make1x1LayoutParams(view));
                        child.setLayoutParams(make2x2LayoutParams(child));
                    } else {
                        child.setLayoutParams(make2x2LayoutParams(child));
                        view.setLayoutParams(make1x1LayoutParams(view));
                    }
                    mGrid.removeView(view);
                    mGrid.addView(view, index);
                    break;
                case DragEvent.ACTION_DROP:
                    for (int i = 0; i < mGrid.getChildCount(); i++) {
                        child = mGrid.getChildAt(i);
                        child.setLayoutParams(make1x1LayoutParams(child));
                    }
                    mGrid.removeView(view);
                    if (index == 0) {
                        view.setLayoutParams(make2x2LayoutParams(view));
                    }
                    mGrid.addView(view, index);
                    view.setVisibility(View.VISIBLE);
                    mGrid.getChildAt(0).setLayoutParams(make2x2LayoutParams(mGrid.getChildAt(0)));
                    break;
                case DragEvent.ACTION_DRAG_ENDED:
                    if (!event.getResult()) {
                        view.setVisibility(View.VISIBLE);
                    }
                    break;
            }
            return true;
        }
    }

    private void startScrolling(int from, int to) {
        if (from != to && mAnimator == null) {
            isScroll = true;
            mAnimator = new ValueAnimator();
            mAnimator.setInterpolator(new OvershootInterpolator());
            mAnimator.setDuration(Math.abs(to - from));
            mAnimator.setIntValues(from, to);
            mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
                    mScrollView.smoothScrollTo(0, (int) valueAnimator.getAnimatedValue());
                }
            });
            mAnimator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    isScroll = false;
                    mAnimator = null;
                }
            });
            mAnimator.start();
        }
    }

    private void stopScrolling() {
        if (mAnimator != null) {
            mAnimator.cancel();
        }
    }

    private int calculateNextIndexOld(float x, float y) {
        // calculate which column to move to
        final float cellWidth = mGrid.getWidth() / mGrid.getColumnCount();
        final int column = (int) (x / cellWidth);

        final float cellHeight = mGrid.getHeight() / mGrid.getRowCount();
        final int row = (int) Math.floor(y / cellHeight);

        int index = row * mGrid.getColumnCount() + column;
        if (index >= mGrid.getChildCount()) {
            index = mGrid.getChildCount() - 1;
        }
        Log.d("MainActivity", "<<<<index=" + index);
        return index;
    }

    private int calculateNextIndex(float x, float y) {
        // calculate which column to move to
        int index;

        for (index = 0; index < mGrid.getChildCount(); index++) {
            View child = mGrid.getChildAt(index);
            Rect rect = new Rect();
            child.getHitRect(rect);
            if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom) {
                break;
            }
        }
        if (index >= mGrid.getChildCount()) {
            // Move into empty cell? Calculate based upon uniform cell sizes.
            index = calculateNextIndexOld(x, y);
        }
        if (index >= mGrid.getChildCount()) {
            // Can't determine where to put it? Add it to the end.
            index = mGrid.getChildCount() - 1;
        }
        return index;
    }
}

如果你稍微尝试一下这个演示,你会发现可以移动瓷砖,使得出现一个1x1的间隙。这也许没关系,但如果有需要的话,代码可能需要进行一些重新调整。

{btsdaf} - Furqan
@Furqan GridLayout 是一个由3列5行组成的布局。我对你在拖动到第三行时期望的调整大小不太清楚。你能进一步解释一下吗? - Cheticamp
我的意思是,当您将数字1拖动到任何位置时,数字1应该调整为正常大小,其他数字替换数字的位置并将其大小调整为更大。简而言之,在位置0处的数字大小保持不变,但其他数字可以在放置到0时自适应大小。 - Furqan
有没有拖动位置的解决方案?我想检查一下,如果在拖动位置有图像可用,那么我想把它放在那里,否则我不想放。 - Dhara Patel
你有演示吗?请与我们分享。 - Ravi Vaghela
请问LongPressListener是什么? - bugfreerammohan

-1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接