Algorithm help needed - rows/columns in a grid - android

I have been killing myself trying to develop an algorithm to determine the positions of the cells in a grid by which row or column they are in.
For example, I have an 8x8 grid and I need to determine all of the positions of the cells in row 3.
The issue that I have is that, without alot of loops, I need to figure out a way to map the position clicked to the row and column that contain that cell.
Here is what I did to create an ArrayList of the cells:
public class GameBoard {
public ArrayList<Row> rows = new ArrayList<Row>();
public ArrayList<Column> columns = new ArrayList<Column>();
private int maxPositions;
public GameBoard(int rowCount, int colCount) {
this.maxPositions = (rowCount * colCount) - 1;
for(int x = 0;x < rowCount;x++){
Row row = new Row(x);
row.cells.addAll(this.getRowCells(x, colCount));
rows.add(row);
}
for(int x = 0;x < colCount;x++){
Column column = new Column(x);
column.cells.addAll(getColumnCells(x, colCount));
columns.add(column);
}
}
private ArrayList<Cell> getRowCells(int rowId, int colCount) {
ArrayList<Cell> row_cells = new ArrayList<Cell>();
int first_position = ((rowId * colCount) -1);
Cell cell = new Cell();
cell.id = first_position;
row_cells.add(cell);
int x = 1;
while(x < colCount) {
cell = new Cell();
cell.id = first_position + x;
row_cells.add(cell);
x++;
}
return row_cells;
}
private ArrayList<Cell> getColumnCells(int columnId, int rowCount) {
ArrayList<Cell> col_cells = new ArrayList<Cell>();
int first_position = columnId;
Cell cell = new Cell();
cell.id = first_position;
col_cells.add(cell);
int x = 1;
while(x < rowCount) {
cell = new Cell();
cell.id = rows.get(x).cells.get(columnId).id;
col_cells.add(cell);
x++;
}
return col_cells;
}
public Cell getColumnNextCell(int position, int columnId) {
Cell cell = null;
if ((position > -1) && (position <= maxPositions)) {
cell = columns.get(columnId).cells.get(position + 1);
}
return cell;
}
public Cell getColumnPreviousCell(int position, int columnId) {
Cell cell = null;
if ((position > 0) && (position <= maxPositions)) {
cell = columns.get(columnId).cells.get(position - 1);
}
return cell;
}
public Cell getRowNextCell(int position, int rowId) {
Cell cell = null;
if ((position > -1) && (position <= maxPositions)) {
cell = rows.get(rowId).cells.get(position + 1);
}
return cell;
}
public Cell getRowPreviousCell(int position, int rowId) {
Cell cell = null;
if ((position > 0) && (position <= maxPositions)) {
cell = rows.get(rowId).cells.get(position - 1);
}
return cell;
}
}
As you can see with the methods like getColumnNextCell() through getRowPreviousCell() the logic is a mess and I am stuck on how to determine the column and row of the clicked cell (as I explained). Any help would be greatly appreciated.
For clarification the Row and Column objects are identical. They look like this.
public class Column {
public int id;
public ArrayList<Cell> cells = new ArrayList<Cell>();
public Column(int idx) {
this.id = idx;
}
}

Can't you just use an array for the cells
int rows, cols;
Cell[][] cells;
public GameBoard(int rowCount, int colCount) {
this.maxPositions = (rowCount * colCount) - 1;
this.rows = rowCount;
this.cols = colCount;
this.cells = new Cell[rows];
for(int i=0; i < rows; i++) {
cells[i] = new Cell[cols];
for(int j = 0; j < cols; j++) {
cells[i][j] = new Cell();
// whatever else you need to do...
}
}
}
This way it would be easy to get the cell you want
Cell getCell(int position) {
return cells[position/rows][position%cols];
}

Why don't you use simple two dimensional array? If your grid is not resized after creation, there is no advantage of using ArrayList objects. So what about having your base class something like this:
public class GameBoard {
private Cell[][] cells;
private int maxPositions;
private int rows;
private int cols;
public GameBoard(int rowCount, int colCount) {
this.rows = rowCount;
this.cols = colCount;
cells = new Cell[rowCount][colCount];
for (int i = 0; i < rowCount; i++) {
for (int j = 0; j < colCount; j++) {
cells[i][j] = new Cell();
}
}
this.maxPositions = (rowCount * colCount) - 1;
}
...
}
Now you don't have row and column objects, just array of cells. Isn't those cells actually what you need or do those row and column arrays have another purpose? So I think you are trying to do simple thing with too difficult way.

Related

maze example not generating maze

I am following Maze game tutorial from youtube Android Programming - Maze Game Pt4
The tutor's code in the video generates random mazes. I have followed the code to the 'T' throughout but my emulator only gives the following output -
My emulator's output
Here is my code. Can anyone tell me what i missed from the tutorial I was following or if the tutorial itself has some coding errors? -
public class MazaGame extends View {
private Cell[][] cells;
private static final int COLS = 7, ROWS = 10;
private static final float WALL_THICKNESS = 4;
private float cellSize,hMargin,vMargin;
private Paint wallPaint;
private Random random;
public MazaGame(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
wallPaint = new Paint();
wallPaint.setColor(Color.BLACK);
wallPaint.setStrokeWidth(WALL_THICKNESS);
random = new Random();
createMaze();
}
private Cell getNeighbor(Cell cell){
ArrayList<Cell> neighbors = new ArrayList<>();
//left neighbor
if(cell.col >0)
if(!cells[cell.col-1][cell.row].visited)
neighbors.add(cells[cell.col-1][cell.row]);
//right neighbor
if(cell.col < COLS-1)
if(!cells[cell.col+1][cell.row].visited)
neighbors.add(cells[cell.col+1][cell.row]);
//top neighbor
if(cell.row >0)
if(!cells[cell.col][cell.row-1].visited)
neighbors.add(cells[cell.col][cell.row-1]);
//bottom neighbor
if(cell.row < ROWS-1)
if(!cells[cell.col][cell.row+1].visited)
neighbors.add(cells[cell.col][cell.row+1]);
if(neighbors.size()>0) {
int index = random.nextInt(neighbors.size());
return neighbors.get(index);
}
return null;
}
private void removeWall(Cell current, Cell next){
if(current.col == next.col && current.row == next.row+1){
current.topWall = false;
next.bottomWall = false;
}
if(current.col == next.col && current.row == next.row-1){
current.bottomWall = false;
next.topWall = false;
}
if(current.col == next.col+1 && current.row == next.row){
current.leftWall = false;
next.rightWall = false;
}
if(current.col == next.col-1 && current.row == next.row){
current.rightWall = false;
next.leftWall = false;
}
}
private void createMaze() {
Stack<Cell> stack = new Stack<>();
Cell current, next;
cells = new Cell[COLS][ROWS];
for (int x = 0; x < COLS; x++) {
for (int y = 0; y < ROWS; y++) {
cells[x][y] = new Cell(x, y);
}
}
do {
current = cells[0][0];
current.visited = true;
next = getNeighbor(current);
if (next != null) {
removeWall(current, next);
stack.push(current);
current = next;
current.visited = true;
} else
current = stack.pop();
}while (!stack.empty());
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.RED);
int width = getWidth();
int height = getHeight();
if(width/height < COLS/ROWS)
cellSize = width/(COLS+1);
else
cellSize = height/(ROWS+1);
hMargin = (width-COLS*cellSize)/2;
vMargin = (height-ROWS*cellSize)/2;
canvas.translate(hMargin,vMargin);
for(int x=0;x<COLS;x++){
for(int y=0;y<ROWS;y++){
if(cells[x][y].topWall)
canvas.drawLine(
x*cellSize,
y*cellSize,
(x+1)*cellSize,
y*cellSize,
wallPaint);
if(cells[x][y].leftWall)
canvas.drawLine(
x*cellSize,
y*cellSize,
x*cellSize,
(y+1)*cellSize,
wallPaint);
if(cells[x][y].bottomWall)
canvas.drawLine(
x*cellSize,
(y+1)*cellSize,
(x+1)*cellSize,
(y+1)*cellSize,
wallPaint);
if(cells[x][y].rightWall)
canvas.drawLine(
(x+1)*cellSize,
y*cellSize,
(x+1)*cellSize,
(y+1)*cellSize,
wallPaint);
}
}
}
private class Cell{
boolean
topWall = true,
rightWall = true,
bottomWall = true,
leftWall = true,
visited = false;
int col,row;
public Cell(int col, int row) {
this.col = col;
this.row = row;
}
}
}
I'm not going to take the time to fully internalize 100% of the code you posted, but this section looks suspicious:
do {
current = cells[0][0];
current.visited = true;
next = getNeighbor(current);
if (next != null) {
removeWall(current, next);
stack.push(current);
current = next;
current.visited = true;
} else
current = stack.pop();
}while (!stack.empty());
I suspect you want this to look like this instead:
current = cells[0][0];
current.visited = true;
do {
next = getNeighbor(current);
if (next != null) {
removeWall(current, next);
stack.push(current);
current = next;
current.visited = true;
} else
current = stack.pop();
}while (!stack.empty());
What you have right now will continuously reset current to be the cell at (0,0), because every time through the loop, you're executing
current = cells[0][0];
current.visited = true;
I suspect that this is just supposed to be the initial setup for the first cell, and you don't want this happening every time through the loop.

Generate Random no between x and y whose sum is m

I want to generate n no of random no whose sum should be m and these no should always be between x and y.
For eg :- If i say I need 20 no, between 3 and 9 inclusive, whose sum should be 100.
I want to specify the sum and required amount of no as well as the limit between which random no should be generated and it should give me the random no of specified amount. Below is my code which do generates no which are greater than 2 but i am not able to put the max limit. Also, the sum which comes out and the sum of no. which it generates is not equal to specified sum. I am totally confused Please help me out.
TextView textView,randomTotaltxt;
int count0 = 0;
int count1 = 0;
int targetSum = 100;
int numberofDraws = 20;
textView = (TextView) findViewById(R.id.textview);
randomTotaltxt = (TextView) findViewById(R.id.randomTptalText);
Random r = new Random();
ArrayList<Integer> load = new ArrayList<>();
//random no
int sum = 0;
for (int i=0; i<numberofDraws;i++){
int next = r.nextInt(targetSum)+1;
Log.d("No",""+next);
load.add(next);
sum += next;
}
//scale it
double scale = 1d*targetSum/sum;
sum=0;
for (int i=0; i<numberofDraws;i++){
load.set(i, (int)(load.get(i)*scale));
sum += load.get(i);
}
while (load.contains(0)|| load.contains(1)){
for (int i=0; i<load.size();i++) {
if (load.get(i).equals(0)) {
load.set(i, load.get(i) + 2);
count0++;
sum = sum+1;
}
if (load.get(i).equals(1)) {
load.set(i, load.get(i) + 2);
sum += load.get(i);
count1++;
sum = sum+1;
}
}
}
// take rounding
while (sum++ <targetSum){
int i = r.nextInt(numberofDraws);
load.set(i, load.get(i) + 1);
}
textView.setText(""+load);
randomTotaltxt.setText(""+(sum-1));
This might not be the optimal solution but this will do your work as required.
int targetSum = 100;
int numberOfDraws = 20;
int uppr=0;
int countt =0;
ArrayList<Integer> load = new ArrayList<>();
Random random;
TextView textView1,randomTotaltxt1;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
textView1 = (TextView) findViewById(R.id.textview1);
randomTotaltxt1 = (TextView) findViewById(R.id.randomTptalText1);
random = new Random();
//random no
int sum = 0;
for (int i=0; i<numberOfDraws;i++){
int next = random.nextInt(targetSum)+1;
load.add(next);
sum += next;
}
//scale it
double scale = 1d*targetSum/sum;
sum=0;
for (int i=0; i<numberOfDraws;i++){
load.set(i, (int)(load.get(i)*scale));
sum += load.get(i);
}
// take rounding
while (sum++ <targetSum){
int i = random.nextInt(numberOfDraws);
load.set(i, load.get(i) + 1);
Log.d("TAG",""+load);
}
checkForUpperRange();
}
public void checkForUpperRange(){
for (int i=0; i<numberOfDraws;i++){
int n = load.get(i);
if (n > 9){
load.set(i, 9);
uppr = n - 9; // getting the required no.
adjustUpper();
break;
}
checkForLowerRange();
}
}
private void adjustUpper() {
for (int j=0; j<numberOfDraws;j++){
if (load.get(j) > 2){
load.set(j, load.get(j)+uppr); // uppr is added
checkForUpperRange();
break;
}
}
}
public void checkForLowerRange(){
for (int i=0; i<numberOfDraws;i++){
int n = load.get(i);
if (n == 0){
load.set(i, load.get(i)+3); // 3 is added in sum
adjust0();
break;
}
if (n == 1){
load.set(i, load.get(i)+2); // 2 is added in sum
adjust1();
break;
}
if (n == 2){
load.set(i, load.get(i)+1); // 1 is added in sum
adjust2();
break;
}
getCount();
}
}
public void getCount(){
countt = 0;
for (int k=0; k<numberOfDraws;k++){
countt = countt+ load.get(k);
showResult();
}
}
public void showResult(){
textView1.setText(""+load);
randomTotaltxt1.setText(""+countt);
}
public void adjust0(){
for (int j=0; j<numberOfDraws;j++){
if (load.get(j) > 3){
load.set(j, load.get(j)-3); // 3 is subtracted
checkForLowerRange();
break;
}
}
}
public void adjust1(){
for (int j=0; j<numberOfDraws;j++){
if (load.get(j) > 3){
load.set(j, load.get(j)-2); // 2 is subtracted
checkForLowerRange();
break;
}
}
}
public void adjust2(){
for (int j=0; j<numberOfDraws;j++){
if (load.get(j) > 3){
load.set(j, load.get(j)-1); // 1 is subtracted
checkForLowerRange();
break;
}
}
}

TimeStamp on Custom X-Labels with an array of 1 value

I have this issue with the xlabels in aChartEngine when there is one value in an ArrayList. I generate my own XLabels for a line chart, but when there is one data array value, i get an unwanted TimeStamp on top of my generated XLabels.
my Code:
private XYMultipleSeriesDataset getDemoDataset() {
Calendar cal = Calendar.getInstance();
Date date = new Date();
date_value = new String[list.size()];
value_value = new String[list.size()];
for(int k = 0; k < list.size(); k++){
date_value[k] = list.get(k).get(DATE);
value_value[k] = list.get(k).get(VALUE);
}
TimeSeries series = new TimeSeries("Line Graph");
for(int j=0; j < date_value.length; j++) {
series.add(formatter.stringToDate(date_value[j]), Integer.parseInt());
}
XYMultipleSeriesDataset dataset = new XYMultipleSeriesDataset();
dataset.addSeries(series);
return dataset;
}
setChartSetting:
private void setChartSetting(XYMultipleSeriesRenderer renderer){
renderer.setXRoundedLabels(true);
renderer.setXTitle("DATES");
renderer.setYTitle(kpiname);
renderer.setApplyBackgroundColor(true);
renderer.setFitLegend(false);
renderer.setAxesColor(Color.DKGRAY);
renderer.setShowGrid(true);
renderer.setZoomEnabled(false);
renderer.setXLabels(0);
renderer.setYLabels(10);
renderer.setZoomEnabled(false, false);
renderer.setPanEnabled(false, false);
//String[] date_value = new String[list.size()];
//String[] value_value = new String[list.size()];
if(list.isEmpty() || list.size() == 0 || list == null ){
return;
}
if(name.equals(RECOVERED) || name.equals(CONVERSION)){
largest_size = (int)Double.parseDouble(value_value[0]);
}else{
if(!(value_value.length == 0)){
largest_size = Integer.parseInt(value_value[0]);
}else{
return;
}
}
//used to determine the maximum value for the y-axis
for(int x =0; x < value_value.length; x++){
if(Integer.parseInt(value_value[x]) > largest_size){
largest_size = Integer.parseInt(value_value[x]);
}
}
renderer.setYAxisMax((double)largest_size);
renderer.setYAxisMin(0);
int value_size = value_value.length;
int m = 0;
//int add = value_size/10;
int add = largest_size/10;
/*instance variables for setting the labels on the X-Axis based on weather the values in the array are
* more than 10 items or less*/
double d;
Long l;
Long l1;
double d1;
if(date_value.length <= 1){
int last = date_value.length;
int mod = 0;
//int add_mod = Math.round(last/10);
int add_mod = (int)Math.round((double)Math.round(last));
l = Long.valueOf(formatter.stringToDateReport(date_value[0]).getTime());
d = l.doubleValue();
/*tried this to see if i can remove the timestamp*/
//renderer.addXTextLabel(0.0, "");
//renderer.removeXTextLabel(0.0);
//renderer.clearXTextLabels();
renderer.addXTextLabel(d, date_value[0]);
}
else if(date_value.length < 10){
for(int i = 0; i < date_value.length; i++){
if(i >= date_value.length){
break;
}
l = Long.valueOf(formatter.stringToDateReport(date_value[i]).getTime());
d = l.doubleValue();
renderer.addXTextLabel(d, date_value[i]);
}
} else if(date_value.length >= 10){
int last = date_value.length;
//int last = 28;
//Log.d(TAG, "last is " + last);
int mod = 0;
//int add_mod = Math.round(last/10);
int add_mod = (int)Math.round((double)Math.round(last) /10); // do this to get the decimal value with a double and then round to get nearset whole with int
for(int i =0; i < date_value.length; i++){
if(mod >= date_value.length){
break;
}
l1 = Long.valueOf(formatter.stringToDateReport(date_value[mod]).getTime());
d1 = l1.doubleValue();
renderer.addXTextLabel(d1, date_value[mod]);
mod+=add_mod;
}
}
}
}
and then:
chartView = ChartFactory.getLineChartView(context, getDemoDataset(), setChartSettings(renderer));
When there are multiple values, it plots the graph well with my custom XLabels(format is MMM-yyyy), but when there is only one value in the ArrayList, it generates thats time stamp.
here is an image:
This was a bug, indeed. You can download a version including a fix for it feature here.

Images based on Array Values

I have a dice game and I am trying to change the image of the Die that is selected after the dice are rolled to a "Dead Die" image. I have tried everything I can think of and I always end up finding the Value "0" in the Index or something else but never the correct Die.
When the dice is selected it sets it's value to a Negative Number. Example I select 6 it changes the value to -6 and changes the die to the -6 die image
How can I get it to display AND KEEP the "DEAD" image I want.
Here is the area where it gets the Images
//Get the Dice Images
public Integer getImage(int index) {
if (diceValues[index] == 0) {
return letterImages.get(index);
} else {
return diceImages.get((diceValues[index]));
}
}
I have tried changing
return letterImages.get(index);
to every possible combination of everything and when I do get it to change the image it always ends up at "0" or the the current number of dice selected or the some other number that I'm just not sure how it came up with.
Here is the entire DieManager class
package com.mygames.dice;
import java.util.HashMap;
import android.util.Log;
public class DieManager {
// Will return the Indexes of the dice when this is used
public static final int INDEX_FLAG = 1;
// Will return the values of the dice when this is used
public static final int VALUE_FLAG = 2;
// Will return the absolute values of the dice when this is used
public static final int ABS_VALUE_FLAG = 3;
// The array that holds the dice
private int[] diceValues = { 0, 0, 0, 0, 0, 0 };
private HashMap<Integer, Integer> diceImages = new HashMap<Integer, Integer>();
private HashMap<Integer, Integer> deadImages = new HashMap<Integer, Integer>();
private HashMap<Integer, Integer> letterImages = new HashMap<Integer, Integer>();
// Sets #newValue to dieValues[#index]
public void setValue(int index, int newValue) {
Log.w(getClass().getName(), "Index = " + index + " Value = " + newValue);
diceValues[index] = newValue;
}
public DieManager() {
super();
initializeMaps();
}
private void initializeMaps() {
diceImages.put(-6, R.drawable.die6_select);
diceImages.put(-5, R.drawable.die5_select);
diceImages.put(-4, R.drawable.die4_select);
diceImages.put(-3, R.drawable.die3_select);
diceImages.put(-2, R.drawable.die2_select);
diceImages.put(-1, R.drawable.die1_select);
diceImages.put(1, R.drawable.die1_roll);
diceImages.put(2, R.drawable.die2_roll);
diceImages.put(3, R.drawable.die3_roll);
diceImages.put(4, R.drawable.die4_roll);
diceImages.put(5, R.drawable.die5_roll);
diceImages.put(6, R.drawable.die6_roll);
deadImages.put(-1, R.drawable.die1_dead);
deadImages.put(-2, R.drawable.die2_dead);
deadImages.put(-3, R.drawable.die3_dead);
deadImages.put(-4, R.drawable.die4_dead);
deadImages.put(-5, R.drawable.die5_dead);
deadImages.put(-6, R.drawable.die6_dead);
letterImages.put(0, R.drawable.die_no);
letterImages.put(1, R.drawable.die_no);
letterImages.put(2, R.drawable.die_no);
letterImages.put(3, R.drawable.die_no);
letterImages.put(4, R.drawable.die_no);
letterImages.put(5, R.drawable.die_no);
}
public void rollDice() {
boolean isNewRound = (numOnTable() == 0);
for (int j = 0; j < 6; j++) {
// If its a new round then the dice value can be changed from 0.
// Else it can't
if (isNewRound || diceValues[j] != 0)
diceValues[j] = (int) ((Math.random() * 6) + 1);
}
}
// Returns the value or absolute value
public int getValue(int index, int flag) {
if (flag == ABS_VALUE_FLAG)
return Math.abs(diceValues[index]);
return diceValues[index];
}
// If a dice value is 0 then its a letter
public int numOnTable() {
int count = 6;
for (int i : diceValues) {
if (i == 0)
count--;
}
return count;
}
// Picking up makes the dice value 0
public void pickUp(int[] highlighted) {
for (int i = 0; i < highlighted.length; i++)
diceValues[highlighted[i]] = 0;
}
// A negative value means a die is highlighted
public void toggleHighlight(int index) {
diceValues[index] *= -1;
}
public void clearTable() {
diceValues[0] = 0;
diceValues[1] = 0;
diceValues[2] = 0;
diceValues[3] = 0;
diceValues[4] = 0;
diceValues[5] = 0;
}
// Return the dice that aren't 0
public int[] diceOnTable(int flag) {
if (flag == ABS_VALUE_FLAG) {
int[] array = new int[diceValues.length];
for (int i = 0; i < diceValues.length; i++)
array[i] = Math.abs(diceValues[i]);
return array;
}
return diceValues;
}
//Returns dice that are negative
public int[] getHighlighted(int flag) {
int[] dirtyArray = { 0, 0, 0, 0, 0, 0 };
int count = 0;
for (int j = 0; j < 6; j++) {
if (diceValues[j] < 0) {
if (flag == INDEX_FLAG)
dirtyArray[count++] = j;
if (flag == VALUE_FLAG)
dirtyArray[count++] = diceValues[j];
if (flag == ABS_VALUE_FLAG)
dirtyArray[count++] = Math.abs(diceValues[j]);
}
}
int[] cleanArray = new int[count];
//Returns an array of length 0
if (count == 0)
return cleanArray;
System.arraycopy(dirtyArray, 0, cleanArray, 0, count);
return cleanArray;
}
// Finds in dieValues same #value and excludes #index
public int[] findPairs(int index, int flag) {
int[] dirtyArray = { 0, 0, 0, 0, 0, 0 };
int count = 0;
for (int j = 0; j < 6; j++) {
if (j != index
&& Math.abs(diceValues[j]) == Math.abs(diceValues[index])) {
if (flag == INDEX_FLAG)
dirtyArray[count++] = j;
if (flag == VALUE_FLAG)
dirtyArray[count++] = diceValues[j];
if (flag == ABS_VALUE_FLAG)
dirtyArray[count++] = Math.abs(diceValues[j]);
}
}
int[] cleanArray = new int[count];
if (count == 0)
return cleanArray;
System.arraycopy(dirtyArray, 0, cleanArray, 0, count);
return cleanArray;
}
//Get the Dice Images
public Integer getImage(int index) {
if (diceValues[index] == 0) {
return letterImages.get(index);
} else {
return diceImages.get((diceValues[index]));
}
}
//Get the Number of dice remaining that are not 0
public int numDiceRemain() {
int counter = 0;
for (int j = 0; j < diceValues.length; j++) {
if (diceValues[j] > 0)
counter++;
}
return counter;
}
}
The dice value can never be zero on a roll because of the following line in your rollDice() method:
diceValues[j] = (int) ((Math.random() * 6) + 1);
And this seems logical to me. Why would the value on a die ever be zero?

Android Tile Bitmap

I'm trying to load a bitmap in Android which I want to tile. I'm currently using the following in my view to display a bitmap:
canvas.drawBitmap(bitmap, srcRect, destRect, null)
I essentially want to use this bitmap as a background image in my app and would like to repeat the bitmap in both the X and Y directions.
I've seen the TileMode.REPEAT constant for the BitmapShader class but i am not sure if this is to be used for repeating the actual bitmap or is used for applying a filter to the bitmap.
You would do this in the xml instead of the java code. I haven't attempted this myself but I did find this example.
<xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:id="#+id/MainLayout"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="#drawable/backrepeat"
>
then in an xml called backrepeat.xml
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="#drawable/back"
android:tileMode="repeat" />
reference
Figured out the code version:
BitmapDrawable TileMe = new BitmapDrawable(MyBitmap);
TileMe.setTileModeX(Shader.TileMode.REPEAT);
TileMe.setTileModeY(Shader.TileMode.REPEAT);
ImageView Item = new ImageView(this);
Item.setBackgroundDrawable(TileMe);
Then if you have a drawable to tile, this can be used instead to make the BitmapDrawable:
BitmapDrawable TileMe = new BitmapDrawable(BitmapFactory.decodeResource(getResources(), R.drawable.tile));
The backrepeat.xml above is buggy
<bitmap
xmlns:android="http://schemas.android.com/apk/res/android"
android:src="#drawable/tile"
android:tileMode="repeat"
android:dither="true" />
It seems that some people are interested in doing this in a View, at the onDraw method. The following code has worked for me:
bgTile = BitmapFactory.decodeResource(context.getResources(), R.drawable.bg_tile);
float left = 0, top = 0;
float bgTileWidth = bgTile.getWidth();
float bgTileHeight = bgTile.getHeight();
while (left < screenWidth) {
while (top < screenHeight) {
canvas.drawBitmap(bgTile, left, top, null);
top += bgTileHeight;
}
left += bgTileWidth;
top = 0;
}
<xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:id="#+id/MainLayout"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="#drawable/back"
android:tileMode="repeat"
>
This worked fine for me. I did not have to create the bitmap seperately. I used the tileMode attribute in the layout.
Just put this line of codes in the onCreate():-
final Bitmap bmp = BitmapFactory.decodeResource(getResources(),R.drawable.actionbar_bg);
final BitmapDrawable bitmapDrawable = new BitmapDrawable(bmp);
bitmapDrawable.setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
final ActionBar bar = getSupportActionBar();
bar.setBackgroundDrawable(bitmapDrawable);
If you want to repeat the background only vertically you can set the width of your layout to "wrap_content", whereas if you want to set the background to repeat horizontally set the height to "wrap_content". If both height and width are set to "fill_parent" then it will tile in the X and Y directions.
For example, the following code will repeat your background vertically:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:background="#drawable/news_detail_activity_bg">
</LinearLayout>
/* Tiled Layer Bitmap*/
public class TiledLayer {
private int cellWidth;
private int cellHeight;
private int yPosition = 0, xPosition = 0;
private int[][] grid;
private Image image;
private int[] tileXPositions;
private int[] tileYPositions;
private ArrayList animatedTiles;
private int numberOfTiles;
private int numberOfColumns;
private int numberOfRows;
private int gridColumns;
private int gridRows, width, height;
public TiledLayer(Image image, int columns, int rows, int tileWidth,
int tileHeight, int width, int height) {
this.grid = new int[columns][rows];
this.gridColumns = columns;
this.gridRows = rows;
this.width = columns * tileWidth;
this.height = rows * tileHeight;
this.animatedTiles = new ArrayList();
setStaticTileSet(image, tileWidth, tileHeight);
}
public void setStaticTileSet(Image image, int tileWidth, int tileHeight) {
this.image = image;
this.cellWidth = tileWidth;
this.cellHeight = tileHeight;
int columns = 64;//image.getWidth() / tileWidth;
int rows =40;// image.getHeight() / tileHeight;
this.tileXPositions = new int[columns];
int pos = 0;
for (int i = 0; i < columns; i++) {
this.tileXPositions[i] = pos;
pos += tileWidth;
}
this.tileYPositions = new int[rows];
pos = 0;
for (int i = 0; i < rows; i++) {
this.tileYPositions[i] = pos;
pos += tileHeight;
}
if (columns * rows < this.numberOfTiles) {
// clear the grid, when there are not as many tiles as in the
// previous set:
for (int i = 0; i < this.grid.length; i++) {
for (int j = 0; j < this.grid[i].length; j++) {
this.grid[i][j] = 0;
}
}
}
this.numberOfTiles = columns * rows;
this.numberOfColumns = columns;
this.numberOfRows = rows;
}
public int createAnimatedTile(int staticTileIndex) {
if (staticTileIndex >= this.numberOfTiles) {
throw new IllegalArgumentException("invalid static tile index: "
+ staticTileIndex + " (there are only ["
+ this.numberOfTiles + "] tiles available.");
}
this.animatedTiles.add(new Integer(staticTileIndex));
return -1 * (this.animatedTiles.size() - 1);
}
public void setAnimatedTile(int animatedTileIndex, int staticTileIndex) {
if (staticTileIndex >= this.numberOfTiles) {
}
int animatedIndex = (-1 * animatedTileIndex) - 1;
this.animatedTiles.set(animatedIndex, new Integer(staticTileIndex));
}
public int getAnimatedTile(int animatedTileIndex) {
int animatedIndex = (-1 * animatedTileIndex) - 1;
Integer animatedTile = (Integer) this.animatedTiles.get(animatedIndex);
return animatedTile.intValue();
}
public void setCell(int col, int row, int tileIndex) {
if (tileIndex >= this.numberOfTiles) {
throw new IllegalArgumentException("invalid static tile index: "
+ tileIndex + " (there are only [" + this.numberOfTiles
+ "] tiles available.");
}
this.grid[col][row] = tileIndex;
}
public int getCell(int col, int row) {
return this.grid[col][row];
}
public void fillCells(int col, int row, int numCols, int numRows,
int tileIndex) {
if (tileIndex >= this.numberOfTiles) {
throw new IllegalArgumentException("invalid static tile index: "
+ tileIndex + " (there are only [" + this.numberOfTiles
+ "] tiles available.");
}
int endCols = col + numCols;
int endRows = row + numRows;
for (int i = col; i < endCols; i++) {
for (int j = row; j < endRows; j++) {
this.grid[i][j] = tileIndex;
}
}
}
public final int getCellWidth() {
return this.cellWidth;
}
public final int getCellHeight() {
return this.cellHeight;
}
public final int getColumns() {
return this.gridColumns;
}
public final int getRows() {
return this.gridRows;
}
public final void paint(Graphics g) {
int clipX = 0;// g.getClipX();
int clipY = 0;// g.getClipY();
int clipWidth = width;// g.getClipWidth();
int clipHeight = height;// g.getClipHeight();
// jmt restore clip to previous state
int x = this.xPosition;
int y = this.yPosition;
int[][] gridTable = this.grid;
for (int i = 0; i < this.gridColumns; i++) {
int[] gridRow = gridTable[i];
for (int j = 0; j < gridRow.length; j++) {
int cellIndex = gridRow[j];
if (cellIndex != 0) {
// okay this cell needs to be rendered:
int tileIndex;
if (cellIndex < 0) {
Integer tile = (Integer) this.animatedTiles
.get((-1 * cellIndex) - 1);
tileIndex = tile.intValue() - 1;
} else {
tileIndex = cellIndex - 1;
}
// now draw the tile:
g.save(Canvas.CLIP_SAVE_FLAG);
// jmt: clear the screen
Rect r = new Rect(0, 0, cellWidth, cellHeight);
g.clipRect(r);
g.setClip(x, y, this.cellWidth, this.cellHeight);
int column = tileIndex % this.numberOfColumns;
int row = tileIndex / this.numberOfColumns;
int tileX = x - this.tileXPositions[column];
int tileY = y - this.tileYPositions[row];
g.drawImage(this.image, tileX, tileY);
g.restore();
}
y += this.cellHeight;
} // for each row
y = this.yPosition;
x += this.cellWidth;
} // for each column
// reset original clip:
g.setClip(clipX, clipY, clipWidth, clipHeight);
}
}

Categories

Resources