ImageButton Neighboring Validation - android

I have a 4x4 tile of letters. I wanted to have a validation that only those letters nearest to the tapped/clicked/pressed letter must be clickable and others are set as unclickable. I have my code (see below) for image1. I am having a second thought of how will I enable disabled ImageButton when I tap ImageButton near it.
Example of set:
1 | 5 | 9 | 13
2 | 6 | 10 | 14
3 | 7 | 11 | 15
4 | 8 | 12 | 16
If I clicked/pressed 1 then the 2, 5 and 6 are clickable and the rest are not. Then, I'll click 2 and 1, 3, 5, 6 and 7 must be clickable.
QUESTIONS:
How can I avoid button being clicked again if its already clicked?
How can I enable disabled button and avoiding my Q1?
I am using Android Studio.
Code
if (image1.isPressed()) {
image1.setClickable(false);
image2.setClickable(true);
image3.setClickable(false);
image4.setClickable(false);
image5.setClickable(true);
image6.setClickable(true);
image7.setClickable(false);
image8.setClickable(false);
image9.setClickable(false);
image10.setClickable(false);
image11.setClickable(false);
image12.setClickable(false);
image13.setClickable(false);
image14.setClickable(false);
image15.setClickable(false);
image16.setClickable(false);
}
TIA :)

Avoid writing conditional code. Writing if for each and every image click is a bad practice. So, you can create an arraylist which will always hold the clickable buttons. Based on the clicked button, change this arraylist. Pass this list to a method, which shall enable or disable the clicks for you.

This isn't really about ImageButtons, but rather, what algorithm or methodology would you use to determine which regions are clickable, based on the current state of the system.
We need to separate the logic somewhat. On one side you have your View. Let's just put everything related to updating your grid into a black box, say void updateGrid(List<List< Boolean>> grid). Let's maintain a matrix with entries determining whether or not a button is clickable.
Initially all of the buttons are clickable. You're going to get some notification when a button is clicked, say from a callback void onButtonClick(int i, int j), where i and j give the position of the button. I'm deliberately being vague about this, you'll most likely get an id, and need to resolve the i and j positions yourself. In which case perhaps you'll want to encapsulate the buttonStates and positions in some kind of object - it's up to you.
private <List<List<Boolean>> mGrid;
private static final int GRID_LENGTH = ...;
private static final int GRID_WIDTH = ...;
private static final defaultValue = false;
public void onButtonClick(int i, int j) {
List<List<Boolean>> newGrid = selectGridRegion(i, j);
updateGrid(newGrid);
}
private List<List<Boolean>> selectGridRegion(int i, int j) {
if (!isValidRegion(i, j)) {
return mGrid;
}
ArrayList<ArrayList<Boolean>> grid = makeGrid();
for (int row = 0; row < GRID_LENGTH; row++) {
ArrayList<Boolean> gridRow = grid.get(row);
for (int col = 0; col < GRID_WIDTH; col++) {
gridRow.set(col, isNeighboringRegion(i, j, row, col));
}
}
return grid;
}
private static boolean isNeighboringRegion(int i, int j, int m, int n) {
return (Math.abs(i - m) == 1 && Math.abs(j - n) == 1);
}
private static List<List<Boolean>> makeGrid() {
ArrayList<ArrayList<Boolean>> grid = new ArrayList<ArrayList<Boolean>>();
for (int i = 0; i < GRID_LENGTH; i++) {
ArrayList<Boolean> row = new ArrayList<Boolean>();
for (int j = 0; j < GRID_WIDTH; j++) {
row.add(defaultValue);
}
grid.add(row);
}
return grid;
}
private static boolean isValidRegion(int i, int j) {
boolean isValid = false;
if (0 <= i && i < GRID_LENGTH) {
if (0 <= j && j < GRID_WIDTH) {
isValid = true;
}
}
return isValid;
}
Now, that's a general approach to modeling the grid. All these method except for onButtonClick sound very much like they should be encapsulated in a Grid class! You might want to extend ArrayList, or something similar.

Related

Getting numbers from 1 to 4 in a random order

I want to get 4 random value(different from each other) 1 to 4 in Android.
I wrote a code like this. But the values aren't different from each other.
Random random = new Random();
int number, idSearch[]=new int[4];
number = random.nextInt(4);
idSearch[0] = number;
for (int i = 1; i < 4; i++)
{
number = (int) random.nextInt(4);
for (int j = 0; j <= i; j++)
{
if (idSearch[j] == number) {
number = random.nextInt(4);
}
}
idSearch[i] = number;
}
Where is error? Can you help me?
I reckon the easiest way of generating a List<Integer> with values from 1 to 4 (inclusive) in a random order would be to first create a List<Integer> with the initial values and shuffle it:
List<Integer> list = Arrays.asList(1, 2, 3, 4);
Collections.shuffle(list);
System.out.println(list);
>> [4, 1, 3, 2]
Keep in mind that this list cannot be added to or removed from.
If you would like it to be mutable, simply pass it to the constructor of an ArrayList:
List<Integer> mutableList = new ArrayList<>(list);
Remember to import java.util.*
If you are using JDK1.8 then you can generate numbers from 1 to 4 in random order, you can use new Random().ints() as shown below:
int[] randoms = new Random().ints(1,5).distinct().limit(4).distinct().toArray();
If you are using JDK1.7 or earlier, you need to use Collections.shuffle() rather than you re-inventing the shuffling the logic.
You have to create new object Random and pls use second for behind fist for.

Android onInterceptTouchEvent, get childs in ViewGroup

I have a layout(like board) like this that contains cells(buttons)
| A | B | C | D |
-----------------
| E | F | G | H |
-----------------
| I | J | K | L |
-----------------
| X | Y | Z | W |
I'm adding Cells programmatically, they contains letters I set.
public void addCells(String letters){
removeAllViews();
int let = 0;
for (int j = 0; j < 4; j++){
for (int i = 0; i < 4; i++){
String currentLetter = ""+letters.charAt(let);
//Cell object that contains it's position and letter.
Cell cell_ = new Cell(this.getContext(), new Point(i , j), new Letter(currentLetter));
this.addView(cell_);
this.cells[i][j] = cell_;
let++;
}
}
}
My aim is connecting cells by finger moving like this:
I'm returning true from onTouchEvent() so I can capture all touchs in ViewGroup onInterceptTouchEvent()
public boolean onTouchEvent(MotionEvent motionEvent) {
return true;
}
But I couldn't get the logic. How can I access a certain child object by click/touch in that ViewGroup?
When I click to 'A' letter, I want to access that cell object.
In general:
The parent view intercepts all touch events (x,y)
onInterceptTouchEvent() { return true; }
On touch event, the parent finds the inner view that match the event location
onTouchEvent() { // see below }
Perform action on that view (Light it up, update data, etc)
How the parent can find the inner view?
You can do it in 2 ways,
1) Have a data structure ([][]) for the board that holds a reference to the cells views. Then you know what is the touch event X,Y so if all cells are equal simply calculate the correct cell based on the cells size and location.
View[][] board;
// Add the Views to the board in creation loop
int cellWidth = board[0][0].getMeasuredWidth();
int cellHeight = board[0][0].getMeasuredHeight();
int tragetX = (int)(x / cellWidth);
int targetY = (int)(y / cellHeight);
View targetCell = board[targetX][targetY];
// Do something with targetCell
2) Iterate on all the parent children (last to first is best), and calculate the child view location inside the parent location and with combination of it's size determine if that child is the target or not.
View targetChild = null;
int[] loc = new int[2];
for (int i = getChildCount()-1; i >= 0; i--) {
View child = getChildAt(i);
child.getLocationInWindow(loc);
if (x >= loc[0] && x <= loc[0]+child.getMeasuredWidth() &&
y >= loc[1] && y <= loc[1]+child.getMeasuredHeight()) {
targetChild = child;
break;
}
}
// Do something with targetChild
The above is an example, please write a better code :) (reuse loc, etc...)

Interchange positions of two Views within GridLayout (Android)

I have programmed a basic gaming App that consists of blocks which can be exchanged by a swipe (similar to CandyCrush). I succeeded in recognizing the swipe gesture but my code that changes the positions of the Views (blocks) within a GridLayout does only work in the emulator but not on a real device (Samsung Galaxy S3).
Also I couldn't find a way of animating the interchange of the two views. I've added android:animateLayoutChanges="true" to the GridLayout XML but it didn't change anything.
Here's my exchanging code:
// change to blocks positions in grid layout
GridLayout.LayoutParams sourceParams = (GridLayout.LayoutParams)this.imageView.getLayoutParams();
GridLayout.LayoutParams targetParams = (GridLayout.LayoutParams)otherBlock.imageView.getLayoutParams();
GridLayout.Spec sourceRowSpec = sourceParams.rowSpec;
GridLayout.Spec sourceColumnSpec = sourceParams.columnSpec;
sourceParams.rowSpec = targetParams.rowSpec;
sourceParams.columnSpec = targetParams.columnSpec;
targetParams.rowSpec = sourceRowSpec;
targetParams.columnSpec = sourceColumnSpec;
this.imageView.setLayoutParams(sourceParams);
otherBlock.imageView.setLayoutParams(targetParams);
gameGridLayout.requestLayout();
And here's a screenshot of the App:
You should have an index table of your layout, and in your drawing method you run through this index to draw each block.
Like that:
private int [][] index;
void onDraw(Canvas canvas) {
for (int i = 0; i < MAX_BLOCK_HEIGHT; i++) {
for (int j = 0; j < MAX_BLOCK_WIDTH; j++) {
// Draw block index[i][j]
}
}
}
void swapBlock(int blockX, int blockY, int relativePos) {
int tmpBlock = index[blockY][blockX];
if (relativePos == AT_LEFT) {
index[blockY][blockX] = index[blockY][blockX - 1];
index[blockY][blockX - 1] = tmpBlock;
}
// And so on...
}
And this index can be helpful all the time, not only for blit.

How to programmatically adjust z order of Views

The below code is my attempt to send mMyView to the front or the back of the set of children of mPivotParent so it will be rendered on top or behind the others. Hiding the view will not suffice in my case.
mPivotParent is a FrameLayout.
Looking at mPivotParent.mChildren shows that my code below "works" in that the ordering is being set correctly. Yet it has no impact on the z order. Not only this, but the framerate gets cumulatively slower and slower the more times the repositioning code gets called. There are 4 children total and mPivotParent.mChildrenCount remains at 4 throughout as expected.
I'm targeting API Level 7.
#Override
public boolean onTouchEvent(MotionEvent event) {
Display display = getWindowManager().getDefaultDisplay();
float x = event.getRawX();
float sWidth = (int)display.getWidth();
float xLerpFromCenter = ((x / sWidth) - .5f) * 2.f; // [-1, 1]
mRotateAnimation.mfLerp = xLerpFromCenter;
if(xLerpFromCenter < -0.2f && mPivotParent.getChildAt(0) != mMyView)
{
mPivotParent.removeView(mMyView);
mPivotParent.addView(mMyView, 0);
refreshEverything();
}
else if(xLerpFromCenter > 0.2f && mPivotParent.getChildAt(0) == mMyView)
{
mPivotParent.removeView(mMyView);
mPivotParent.addView(mMyView, mPivotParent.getChildCount() - 1);
refreshEverything();
}
return super.onTouchEvent(event);
}
private void refreshEverything()
{
for(int i = 0; i < mPivotParent.getChildCount(); ++i)
{
mPivotParent.getChildAt(i).invalidate();
mPivotParent.getChildAt(i).requestLayout();
}
mPivotParent.invalidate();
mPivotParent.requestLayout();
}
Partial Solution
Here's a somewhat inefficient hack but it works for my purpose, which is to take the top item and send it to the back, keeping all other items in their same order.
private void putFrontAtBack()
{
for(int i = 0; i < mPivotParent.getChildCount() - 1; ++i)
{
mPivotParent.getChildAt(0).bringToFront();
}
refreshEverything();
}
Note: This doesn't work in the general case of arbitrary re-ordering.
Try this.
private void reorder(int[] order)
{
if(order == null || order.length != mPivotParent.getChildCount()) return;
for(int i = order.length - 1; i >= 0; i--)
{
mPivotParent.getChildAt(order[i]).bringToFront();
}
refreshEverything();
}
This code provides arbitrary reordering. The integer array "order" is used to indicate the new order of each view, where order[n]=x means the new order of childAt(x) is n.

How to change direction of drawing children of grid to Right_To_Left in Android

Im trying to use grid but I need to change direction of inserting children from ( left to right ) to ( right to left ). is there any way to do so , simple example would help me more.
Thanks in advance.
I wrote this. I think solve your problem
/** Returns inverted list by step that take. for example if our list is {1, 2, 3, 4, 5, 6,
* 7 ,8 ,9} and step is 3 inverted list is this: {3, 2, 1, 6, 5, 4, 9, 8, 7}
*/
public static <E> ArrayList<E> invert(List<E> source, int step){
List<E> inverted = new ArrayList<E>();
for(int i = 0; i < source.size(); i++){
if((i + 1) % step == 0){
for(int j = i, count = 0; count < step; j--, count++){
inverted.add(source.get(j));
}
}
}
//
// When (source.size() % step) is not 0 acts.this is for last of list. add last part
// of the source that wasn't add.
//
int remainder = source.size() % step;
if((remainder) != 0 ){
for (int j = source.size() - 1, count = 0; count < (remainder); j--, count++) {
inverted.add(source.get(j));
}
}
return (ArrayList<E>) inverted;
}
i guess the only way is creating a custom gridview, overriding the onLayout() method.
take a look here.
or maybe you can invert items for each row in the list adapter? like for a 3-columns grid, instead of
[1 2 3][4 5 6][7 8] -->
[3 2 1][6 5 4][null 8 7].
(i admit i never used gridview)
i have face same problem but finally solved using reset Array
Here change only u r column no = 3
ArrayList<String> tb_ith_sections_list = new ArrayList<String>;
tb_ith_sections_list = dbhelper.getArrayList();
int sectionCount = tb_ith_sections_list.size();
if(sectionCount > 0){
int rowCount =sectionCount/4;
int colCount ;
if(sectionCount > 4){
colCount=4;
}else{
colCount = sectionCount;
}
if(colCount>sectionCount){
colCount=sectionCount;
}
int k=colCount;
int m=0;
for(int j=0;j<rowCount;j++){
m=(j*colCount);
k=m+colCount;
if(k>sectionCount){
k=(sectionCount-(j*colCount));
}
for(int i=m;i<k;i++){
TB_IVN_SECTIONS tb_Temp=new TB_IVN_SECTIONS();
TB_IVN_SECTIONS tb_ithFirst=tb_ith_sections_list.get(i);
TB_IVN_SECTIONS tb_ithSecond= tb_ith_sections_list.get(k-1);
tb_Temp=tb_ithFirst;
tb_ith_sections_list.set(i, tb_ithSecond);
tb_ith_sections_list.set(k-1,tb_ithFirst);
k--;
}
}

Categories

Resources