Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GridView with colspan and rowSpan

I have been trying to make a gridview with drag and drop functionality along with one cell of different size. I have already made the the grid drag and drop and its working fine. you can check the code from here

my code output

but I want it to be like this and purely dynamic as I will be draging and dropping the other which will be replaced and resized automatically desired output

like image 748
Furqan Avatar asked Oct 15 '17 13:10

Furqan


1 Answers

Updated with new code that accommodates resizing of cells. Your question refers to GridView but the code you supplied doesn't mention GridView but uses GridLayout instead, so I am assuming that GridLayout is the right layout.

I have put together a demo using a mocked-up layout with one 2x2 tile. I have modified the code that you have supplied to accommodate the 2x2 tile. Other than the code that I added to implement the 2x2 tile, the only other change to MainAcitivity was to the calculateNextIndex method that uses a different way of calculating the index at an (x, y) position. Layouts and the LongPressListener class were also mocked up since they were not supplied.

Here is a video of the demo:

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;
    }
}

If you work with the demo a little, you will see that it is possible to move tiles such that a 1x1 tile gap is opened up. This may be OK, but the code may need to be reworked a little if not.

like image 141
Cheticamp Avatar answered Oct 25 '22 19:10

Cheticamp