GridLayout with a dynamic get row / column view

I just followed this tutorial to create a custom View as a GridLayout element.

What's my CustomView

 public class RowView extends View{ boolean touchOn; boolean mDownTouch = false; private OnToggledListener toggledListener; int _IdRow = 0; int _IdColumn = 0; public RowView(Context context, int Rows, int Columns) { super(context); this._IdRow = Rows; this._IdColumn = Columns; init(); } public RowView(Context context) { super(context); init(); } public RowView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public RowView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { touchOn = false; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec)); } @Override protected void onDraw(Canvas canvas) { if (touchOn) { canvas.drawColor(Color.RED); } else { canvas.drawColor(Color.GRAY); } } //onClick not possible to use on custom View so, onTouchEvent is the solution @Override public boolean onTouchEvent(MotionEvent event) { super.onTouchEvent(event); switch (event.getAction()) { //if Click case MotionEvent.ACTION_DOWN: touchOn = !touchOn; invalidate(); if(toggledListener != null){ toggledListener.OnToggled(this, touchOn); } mDownTouch = true; return true; case MotionEvent.ACTION_UP: if (mDownTouch) { mDownTouch = false; performClick(); return true; } } return false; } @Override public boolean performClick() { super.performClick(); return true; } public void setOnToggledListener(OnToggledListener listener){ toggledListener = listener; } public int get_IdRow() { return _IdRow; } public int get_IdColumn() { return _IdColumn; } 

In this class, I can detect when the user clicks on the GridLayout element and changes it to a different color, which is good. But the problem arises at the time to create this:

This is my MainActivity , where I show the GridLayout :

 int numOfCol = mGridLayout.getColumnCount(); int numOfRow = mGridLayout.getRowCount(); mRowViews = new RowView[numOfCol*numOfRow]; for(int yPos=0; yPos<numOfRow; yPos++){ for(int xPos=0; xPos<numOfCol; xPos++){ RowView tView = new RowView(this, xPos, yPos); tView.setOnToggledListener(this); mRowViews[yPos*numOfCol + xPos] = tView; mGridLayout.addView(tView); } } mGridLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener(){ @Override public void onGlobalLayout() { final int MARGIN = 5; int pWidth = mGridLayout.getWidth(); int pHeight = mGridLayout.getHeight(); int numOfCol = mGridLayout.getColumnCount(); int numOfRow = mGridLayout.getRowCount(); int w = pWidth/numOfCol; int h = pHeight/numOfRow; for(int yPos=0; yPos<numOfRow; yPos++){ for(int xPos=0; xPos<numOfCol; xPos++){ GridLayout.LayoutParams params = (GridLayout.LayoutParams)mRowViews[yPos*numOfCol + xPos].getLayoutParams(); params.width = w - 2*MARGIN; params.height = h - 2*MARGIN; params.setMargins(MARGIN, MARGIN, MARGIN, MARGIN); mRowViews[yPos*numOfCol + xPos].setLayoutParams(params); } } }}); 

There is also an Interface OnToggledListener method that gives me the row and column of my GridLayout when an element is clicked on it:

 @Override public void OnToggled(MyView v, boolean touchOn) { //get the id string String idString = v.get_IdRow() + ":" + v.get_IdColumn(); } 

I would like to avoid creating this mGridLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() because it fills things on the screen that I don't need ... I tried putting GridLayout 6x6 with android:layout_height="400dp" and it shows only 3x3 and this is this LogCat message

D / android.widget.GridLayout: vertical limits: y6-y0> = 1749, y6-y5 <= 291, y5-y4 <= 291, y4-y3 <= 291, y3-y2 <= 291, y2 -y1 < = 291, y1-y0 <= 291 are inconsistent; permanent delete: y6-y5 <= 291.

I would like to do something like GridLayout[row][colum] to get the background color and then do something, but I cannot find this solution.

+1
android android-studio grid-layout
Mar 17 '16 at 14:35
source share
1 answer

For simplicity, you can implement a custom Board view that wraps the GridLayout and its associated logic. Below I report on a possible approach.

The wait here is to have an ItemView to represent one single cell on the board.

 public class Board extends FrameLayout implements View.OnClickListener { private GridLayout mGridView; private int mRowsCount; private int mColsCount; private int mCellSpace; private OnItemClickListener mOnItemClickListener; public Board(Context context) { super(context); init(context, null); } // other constructors private void init(Context context, AttributeSet attrs) { // default values mRowsCount = 1; mColsCount = 1; View layout = inflate(getContext(), R.layout.view_lights_board, null); mGridView = (GridLayout) layout.findViewById(R.id.view_grid); mGridView.setRowCount(mRowsCount); mGridView.setColumnCount(mColsCount); mGridView.post(new Runnable() { @Override public void run() { int width = getMeasuredWidth() / getColumnsCount(); int height = getMeasuredHeight() / getRowsCount(); for (int i = 0; i < getRowsCount(); i++) { for (int j = 0; j < getColumnsCount(); j++) { GridLayout.LayoutParams params = (GridLayout.LayoutParams) getChildAt(i, j).getLayoutParams(); params.width = width; params.height = height; getChildAt(i, j).setLayoutParams(params); } } } }); addView(layout); } // this method allows to dinamically create grid public void buildChildren(int rowsCount, int colsCount) { mRowsCount = rowsCount; mColsCount = colsCount; mGridView.setRowCount(mRowsCount); mGridView.setColumnCount(mColsCount); buildChildren(); } public void buildChildren() { for (int i = 0; i < getRowsCount(); i++) { for (int j = 0; j < getColumnsCount(); j++) { ItemView view = new ItemView(getContext(), i, j); view.setOnClickListener(this); mGridView.addView(view); } } } public void setOnItemClickListener(OnItemClickListener listener) { mOnItemClickListener = listener; } public ItemView getChildAt(int rowIndex, int columnIndex) { int index = (getColumnsCount() * rowIndex) + columnIndex; return (ItemView) mGridView.getChildAt(index); } public boolean isTouchOn(int rowIndex, int columnIndex) { return getChildAt(rowIndex, columnIndex).isTouchOn(); } public int getColumnsCount() { return mGridView.getColumnCount(); } public int getRowsCount() { return mGridView.getRowCount(); } @Override public void onClick(View v) { if (v instanceof ItemView) { ItemView view = (ItemView) v; if (mOnItemClickListener != null) { mOnItemClickListener.onItemClick(view); } } } public interface OnItemClickListener { void onItemClick(ItemView view); } } 

In your activity layout you will have something like this (here I assume your application package is com.android.example):

 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="wrap_content" android:layout_height="wrap_content"> <com.android.example.Board android:id="@+id/grid" android:layout_width="match_parent" android:layout_height="400dp" /> </FrameLayout> 

And this is a possible implementation of Activity:

 public class MainActivity extends AppCompatActivity implements LightsOutBoard.OnItemClickListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Board board = (Board) findViewById(R.id.grid); board.setOnItemClickListener(this); board.buildChildren(3, 3); } @Override public void onItemClick(ItemView view) { String text = view.getRowIndex() + " - " + view.getColumnIndex(); Toast.makeText(this, text, Toast.LENGTH_SHORT).show(); } } 

Hope this helps.

+3
Mar 21 '16 at 23:08
source share



All Articles