在触摸该列时上下移动 Gridview 的列

Shift column of Gridview up and down on touch on that column

我有一个 3x3 网格视图。想象如下。

1 2 3
4 5 6
7 8 9

现在我想要实现什么

我希望网格视图的列在触摸时上下移动。

考虑一下,网格视图的第一列。即

1
4
7

现在,如果我触摸此列上的任何位置,无论是在 1 上还是在 4 上或在 7 上,然后在任何一个方向(例如向上或向下)滑动。然后我想将列移动 1 或 2 个位置。

让我澄清一下

如果我通过触摸 7 向上滑动,结果应该是这样的

1
4 2 3
7 5 6 
  8 9

或者,如果我触摸第二列并将其向下方移动,那么它看起来会像下面的东西

1   3
4 2 6
7 5 9
  8

如果我移动 2 个网格单元格的列,那么它将看起来像

1   3
4   6
7 2 9
  5
  8

对于每一列,我应该能够将列移动一个或两个单元格,具体取决于我滚动该列的程度。

还有一件事如果我稍微滚动该列并且它没有将任何网格单元格完全适合所需的位置那么它应该自动适合接近适合该位置的网格单元格。

我在这里搜索了太多关于堆栈溢出的问题并查询了 google 很多。但是我没有得到我真正想要的。

如果我没解释好再告诉我。我会尝试解释更多。 任何想法、任何提示或任何技巧都是值得赞赏的。

编辑

如果我将列移动超过 3 个网格,然后在释放触摸时,列将移动到 只有两个元素。就这样

1   3
4   6
7 2 9
  5
  8

如果我将列移动超过 3 个网格单元格,则它会移动或不移动。如果它移动它移动了多少个细胞?

我没有任何代码块,但我可以解释你如何完成这个任务

您需要像这样创建一个包含空单元格的网格

第 1 -> - - - - - - - - -

第 2 -> - - - - - - - - -

第 3 -> - - - - - - - - -

第 4 -> - - - 1 2 3 - - -

第 5 -> - - - 4 5 6 - - -

第 6 -> - - - 7 8 9 - - -

第 7 -> - - - - - - - - -

第 8 -> - - - - - - - - -

第 9 -> - - - - - - - - -

现在向上滑动获取同一列的所有元素,然后移动到上层

要完成您的要求,您需要负责 GridView 的 canvas,对所触摸的列进行分区,并为拖动、投掷等绘制您自己的绘图。移动完成后,您将需要通过 GridView 对列中的视图进行调整,以保持簿记正常。我会查看讨论视图移动的在线文档。 "Dragging and Scaling" 将是一个很好的起点。

这种方法会有一些“问题”。如果你只是想把它作为一种技术来学习,那么我会说你的方法是可以的。如果您想实现效果并按设计使用 GridView 的底层实现(滚动、边缘效果、flings 等),我建议采用另一种方法。

您可以通过并排对齐三个 1x3 网格视图来构建 GridView 的外观,而不是单个 3x3 GridView。 (实际上,网格视图将是 1x11,以适应垂直幻灯片的最大范围。)如果编码为支持多个网格视图,则每个网格视图都可以由单个适配器支持。由于每一列都是自己的网格视图,因此每一列都可以独立于其他列滑动。

这种方法的优点是您可以在不扭曲底层 GridView class 的情况下获得所需的效果。同样的方法可以使用您现有的使用按钮的方法。


我很好奇如何实施我的建议。下面是一个示例应用程序,其中包含上述三个 GridView 实现以及相同的视频。

MainActivity.java

public class MainActivity extends AppCompatActivity
        implements GridView.OnScrollListener {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        final GridViewAdapter adapter = new GridViewAdapter();

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setupGridView(R.id.gridview0, adapter);
        setupGridView(R.id.gridview1, adapter);
        setupGridView(R.id.gridview2, adapter);
    }

    private void setupGridView(int id, GridViewAdapter adapter) {
        final GridView gridview = (GridView) findViewById(id);

        gridview.setAdapter(adapter);
        // Temporary scroll listener until initial scroll to position is done.
        // This hides the initial movement of the grid cells.
        gridview.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {
                if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {
                    gridview.setOnScrollListener(MainActivity.this);
                }
            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                // Do nothing
            }
        });
        gridview.smoothScrollToPositionFromTop(2, 0);
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {
            final int top = view.getChildAt(0).getTop();
            final int itemHeight = ((GridViewAdapter) (view.getAdapter())).getItemHeight();

            // top <= 0
            if (top > -(itemHeight / 2)) {
                // Less than 1/2 cell height out of place - shift down.
                view.scrollListBy(top);
            } else {
                // Shift up
                view.scrollListBy(top + itemHeight);
            }
        }
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        // Do nothing
    }

    @SuppressWarnings("unused")
    private static final String TAG = "MainActivity";
}

GridViewAdapter.java

class GridViewAdapter extends BaseAdapter {

    GridViewAdapter() {
    }

    @Override
    public int getCount() {
        return mStrings.length / GRID_COLUMN_COUNT;
    }

    @Override
    public Object getItem(int position) {
        return null;
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    // create a new TextView for each item referenced by the Adapter
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        TextView textView;
        final int column = Integer.parseInt((String) parent.getTag());

        if (convertView == null) {
            // if it's not recycled, initialize some attributes
            textView = new TextView(parent.getContext());
            GridView.LayoutParams params =
                    new GridView.LayoutParams(GRID_ITEM_WIDTH, GRID_ITEM_HEIGHT);
            textView.setLayoutParams(params);
            textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
            textView.setGravity(Gravity.CENTER);
        } else {
            // Recycle the view but keep old attributes since they don't change.
            textView = (TextView) convertView;
        }
        textView.setText(mStrings[position * GRID_COLUMN_COUNT + column]);
        return textView;
    }

    int getItemHeight() {
        return GRID_ITEM_HEIGHT;
    }

    private final static String[] mStrings = {
            "", "", "",
            "", "", "",
            "", "", "",
            "", "", "",
            "1", "2", "3",
            "4", "5", "6",
            "7", "8", "9",
            "", "", "",
            "", "", "",
            "", "", "",
            "", "", ""
    };

    private static final int GRID_ITEM_HEIGHT = 150; // in pixels
    private static final int GRID_ITEM_WIDTH = 150; // in pixels
    private static final int GRID_COLUMN_COUNT = 3;

}

activity_main.java

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/linearLayout"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:orientation="horizontal">

    <!-- Sorry for the dimensions in pixels. It just makes everything easier.
    Non-pixel dimensions (dp) should be used here and accommodations made in the code. -->

    <GridView xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/gridview0"
        android:layout_width="150px"
        android:layout_height="1050px"
        android:columnWidth="150px"
        android:horizontalSpacing="0dp"
        android:numColumns="1"
        android:scrollbars="none"
        android:tag="0"
        android:verticalSpacing="0dp" />

    <GridView xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/gridview1"
        android:layout_width="150px"
        android:layout_height="1050px"
        android:columnWidth="150px"
        android:horizontalSpacing="0dp"
        android:numColumns="1"
        android:scrollbars="none"
        android:tag="1"
        android:verticalSpacing="0dp" />

    <GridView xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/gridview2"
        android:layout_width="150px"
        android:layout_height="1050px"
        android:columnWidth="150px"
        android:horizontalSpacing="0dp"
        android:numColumns="1"
        android:scrollbars="none"
        android:tag="2"
        android:verticalSpacing="0dp" />
</LinearLayout>