RelativeLayout changes at run time
I have a puzzle game where the board is a rectangle and the border is made up of piece that are one grid unit long. I have a method that randomizes the images and wraps them around the level, but... it's really terrible. And it has the strangest bug: Depending on what version of Android is running it behaves differently. On 2.1, the borders aren't aligned properly when the activity starts, but they fix themselves as soon as a piece is moved. Not when a piece moves, but when it is moved to a different position (if I were to drag it across the screen and drop it back in the same spot, nothing would happen). When the piece is actually dropped (MotionEvent.ACTION_UP) is when the border corrects itself. In 2.2 it starts of correctly, but when I load a new level (which doesn't start a new activity but calls createBorder again) it acts the same way. Here's what it looks like:
Here is my createBorder method:
private void createBorder(int h, int w, int levelWidthUnits, int levelHeightUnits){
//This method could definitely use some work (understatement), but it's all right for the moment.
//int blankPiece = 0;
int bored = board.getId();
int lastBorder = 0;
int borderWidth = 0;
Matrix m90 = new Matrix();
m90.setRotate(90);
Matrix m180 = new Matrix();
m180.setRotate(180);
Matrix m270 = new Matrix();
m270.setRotate(270);
Bitmap bm1 = BitmapFactory.decodeResource(getResources(), getRandomBorderBitmap());
borderWidth = (int)(bm1.getHeight()/(bm1.getWidth()/((float)(w/levelWidthUnits))));
//Log.i(TAG, "borderWidth = "+borderWidth);
for(int counter=0;counter<levelWidthUnits;counter++){
Bitmap bm = BitmapFactory.decodeResource(getResources(), getRandomBorderBitmap());
Bitmap borderbm = Bitmap.createScaledBitmap(bm, (w/levelWidthUnits), borderWidth, true);
ImageView border = new ImageView(this);
border.setImageBitmap(borderbm);
border.setId(0x90000000+counter);
//border.setImageResource(R.drawable.border_tiki1);
//border.setAdjustViewBounds(true);
//border.setImageMatrix(matrixTop);
//border.setScaleType(ImageView.ScaleType.MATRIX);
LayoutParams params = new LayoutParams(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
if(counter==0){
params.addRule(RelativeLayout.ALIGN_LEFT, bored);
params.addRule(RelativeLayout.ABOVE, bored);
}else{
//Log.i(TAG, "lastBorder before added rule = "+lastBorder);//TODO Why does this only work for the 3rd through 6th pieces?!
params.addRule(RelativeLayout.RIGHT_OF, lastBorder); //This method works just fine for everything but the 2nd piece!
params.addRule(RelativeLayout.ABOVE, bored); //And even for the 2nd piece, this line works! Just not the one above.
}
border.setLayoutParams(params);
game_view.addView(border);
lastBorder = border.getId();
//Log.i(TAG, "lastBorder set to: "+lastBorder);
}
Bitmap cbm = BitmapFactory.decodeResource(getResources(), Theme.getBorderCorner());
Bitmap cornerbm1 = Bitmap.createScaledBitmap(cbm, borderWidth, borderWidth, true);
Bitmap cornerbm = Bitmap.createBitmap(cornerbm1, 0, 0, borderWidth, borderWidth, m90, true);
ImageView border1 = new ImageView(this);
border1.setImageBitmap(cornerbm);
border1.setId(lastBorder+1);
LayoutParams params = new LayoutParams(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.RIGHT_OF, lastBorder);
params.addRule(RelativeLayout.ABOVE, bored);
border1.setLayoutParams(params);
game_view.addView(border1);
lastBorder = border1.getId();
for(int counter=0;counter<levelHeightUnits;counter++){
Bitmap bm2 = BitmapFactory.decodeResource(getResources(), getRandomBorderBitmap());
Bitmap borderbm2 = Bitmap.createScaledBitmap(bm2, (h/levelHeightUnits), borderWidth, true);
Bitmap borderbm1 = Bitmap.createBitmap(borderbm2, 0, 0, (h/levelHeightUnits), borderWidth, m90, true);
ImageView border = new ImageView(this);
border.setImageBitmap(borderbm1);
border.setId(lastBorder+1);
LayoutParams params2 = new LayoutParams(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
params2.addRule(RelativeLayout.RIGHT_OF, bored);
params2.addRule(RelativeLayout.BELOW, lastBorder);
border.setLayoutParams(params2);
((ViewGroup) findViewById(R.id.game_view)).addView(border);
lastBorder = border.getId();
/*if(counter==2){
blankPiece = border.getId();
}*/
//Log.i(TAG, "lastBorder set to: "+lastBorder);
}
Bitmap cbm2 = BitmapFactory.decodeResource(getResources(), Theme.getBorderCorner());
Bitmap cornerbm21 = Bitmap.createScaledBitmap(cbm2, borderWidth, borderWidth, true);
Bitmap cornerbm2 = Bitmap.createBitmap(cornerbm21, 0, 0, borderWidth, borderWidth, m180, true);
ImageView border2 = new ImageView(this);
border2.setImageBitmap(cornerbm2);
border2.setId(lastBorder+1);
LayoutParams params1 = new LayoutParams(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
params1.addRule(RelativeLayout.ALIGN_LEFT, lastBorder);
params1.addRule(RelativeLayout.BELOW, lastBorder);
border2.setLayoutParams(params1);
((ViewGroup) findViewById(R.id.game_view)).addView(border2);
lastBorder = border2.getId();
for(int counter=0;counter<levelWidthUnits;counter++){
Bitmap bm2 = BitmapFactory.decodeResource(getResources(), getRandomBorderBitmap());
Bitmap borderbm2 = Bitmap.createScaledBitmap(bm2, (h/levelHeightUnits), borderWidth, true);
Bitmap borderbm1 = Bitmap.createBitmap(borderbm2, 0, 0, (h/levelHeightUnits), borderWidth, m180, true);
ImageView border = new ImageView(this);
border.setImageBitmap(borderbm1);
border.setId(lastBorder+1);
LayoutParams params2 = new LayoutParams(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
params2.addRule(RelativeLayout.ALIGN_TOP, lastBorder);
params2.addRule(RelativeLayout.LEFT_OF, lastBorder);
border.setLayoutParams(params2);
((ViewGroup) findViewById(R.id.game_view)).addView(border);
lastBorder = border.getId();
//Log.i(TAG, "lastBorder set to: "+lastBorder);
}
Bitmap cbm3 = BitmapFactory.decodeResource(getResources(), Theme.getBorderCorner());
Bitmap cornerbm31 = Bitmap.createScaledBitmap(cbm3, borderWidth, borderWidth, true);
Bitmap cornerbm3 = Bitmap.createBitmap(cornerbm31, 0, 0, borderWidth, borderWidth, m270, true);
ImageView border3 = new ImageView(this);
border3.setImageBitmap(cornerbm3);
border3.setId(lastBorder+1);
LayoutParams params2 = new LayoutParams(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
params2.addRule(RelativeLayout.ALIGN_TOP, lastBorder);
params2.addRule(RelativeLayout.LEFT_OF, lastBorder);
border3.setLayoutParams(params2);
((ViewGroup) findViewById(R.id.game_view)).addView(border3);
lastBorder = border3.getId();
for(int counter=0;counter<levelHeightUnits;counter++){
Bitmap bm2 = BitmapFactory.decodeResource(getResources(), getRandomBorderBitmap());
Bitmap borderbm2 = Bitmap.createScaledBitmap(bm2, (h/levelHeightUnits), borderWidth, true);
Bitmap borderbm1 = Bitmap.createBitmap(borderbm2, 0, 0, (h/levelHeightUnits), borderWidth, m270, true);
ImageView border = new ImageView(this);
border.setImageBitmap(borderbm1);
border.setId(lastBorder+1);
LayoutParams params3 = new LayoutParams(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
params3.addRule(RelativeLayout.LEFT_OF, bored);
params3.addRule(RelativeLayout.ABOVE, lastBorder);
border.setLayoutParams(params3);
((ViewGroup) findViewById(R.id.game_view)).addView(border);
lastBorder = border.getId();
//Log.i(TAG, "lastBorder set to: "+lastBorder);
}
Bitmap cbm4 = BitmapFactory.decodeResource(getResources(), Theme.getBorderCorner());
Bitmap cornerbm41 = Bitmap.createScaledBitmap(cbm4, borderWidth, borderWidth, true);
Bitmap cornerbm4 = Bitmap.createBitmap(cornerbm41, 0, 0, borderWidth, borderWidth, null, true);
ImageView border4 = new ImageView(this);
border4.setImageBitmap(cornerbm4);
border4.setId(lastBorder+1);
LayoutParams params3 = new LayoutParams(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
params3.addRule(RelativeLayout.ALIGN_LEFT, lastBorder);
params3.addRule(RelativeLayout.ABOVE, lastBorder);
border4.setLayoutParams(params3);
((ViewGroup) findViewById(R.id.game_view)).addView(border4);
lastBorder = border4.getId();
}
When a piece is dropped, it test whether or not it has moved. If it has, it calls
counter.setText("Total moves: " + moves); //coun开发者_Go百科ter is a TextView
This is what I believe is somehow causing the layout to fix itself (maybe by asking the screen to redraw itself?). I'm looking for a fix to the strange glitch I'm getting, but if you have a better suggestion on how to wrap these random border pieces, I'd be glad to hear it! (Note: in the future, I want to have level that aren't rectangles but still only have 90 degree angles). Thanks for the help! This is the last bug standing between me and releasing my game!
I'd agree with Gangnus about redrawing everything in this case.
My main reason for replying was for the "if you have a better suggestion on how to wrap these random border pieces, I'd be glad to hear it!" part. It's not that your code is that bad, but you're right that it'll need some work if you want to do non-rectangular maps. Here's my idea for that, at least.
I'd start with a boolean level "map" to define which are "board" and "non-board" squares.
In the base function, loop through each tile. Check whether there's an 'active' tile on each side. If so, call an addBorder()
function with the location and rotation desired.
void createBorders(int widthUnits, int heightUnits, boolean[][] activeMap) {
for(int x=0;x<widthUnits;x++) {
for(int y=0;y<heightUnits;y++) {
if(!activeMap[x][y]) // boolean "map" (true if active)
continue;
if(x == 0)
addBorder(LEFT, x, y);
else if(!activeMap[x-1][y])
addBorder(LEFT, x, y);
if(x == widthUnits-1)
addBorder(RIGHT, x, y);
else if(!activeMap[x+1][y])
addBorder(RIGHT, x, y);
if(y == 0)
addBorder(TOP, x, y);
else if(!activeMap[x][y-1])
addBorder(TOP, x, y);
if(y == heightUnits-1)
addBorder(BOTTOM, x, y);
else if(!activeMap[x][y+1])
addBorder(BOTTOM, x, y);
}
}
}
In the addBorder()
function, get the left and top location of the tile, as in (board.left + (tile.width * x))
for the left, similar for top.
Then you can switch(where)
, and rotate the matrix, size the bitmap, and adjust the location from the tile's base location as needed.
That's about the way I'd do it anyway. That way it works for any tile-based map, even ones with interior inactive areas, without having hard-coded "edges" like you're using now.
I had the similar problem with views with bkg images in 2.2. In LinearLayout. The only way I know is to accept that default layout doesn't work correctly and redraw everything by the code.
精彩评论