I'm currently working on an app that has a RelativeLayout that has 4 child FrameLayouts, each FrameLayout has a set of ImageViews inside it and the inside View has it's own behavior. I'm trying to implement a drag and drop to theFrameLayouts while implementing the onTouchListener I found in this tutorial. but unfortunately the drag 'n drop doesn't work properly and nothing is happening.
any thoughts on how to implement the drag and drop correctly? what am I missing?
here is the xml code for a single child of the FrameLayouts:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="80dp"
android:layout_height="108dp" >
<ImageView
android:id="#+id/secondImage"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:src="#drawable/back" />
<ImageView
android:id="#+id/firstImage"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:src="#drawable/c2" />
</FrameLayout>
here is the xml code for the main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#drawable/pinecropped"
android:orientation="vertical" >
<FrameLayout
android:id="#+id/cardNumber1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="50dp"
android:layout_marginTop="60dp" >
<include layout="#layout/card" />
</FrameLayout>
<FrameLayout
android:id="#+id/cardNumber2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/cardNumber1"
android:layout_marginLeft="50dp"
android:layout_marginTop="100dp" >
<include layout="#layout/card" />
</FrameLayout>
<FrameLayout
android:id="#+id/cardNumber3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="50dp"
android:layout_marginTop="60dp" >
<include layout="#layout/card" />
</FrameLayout>
<FrameLayout
android:id="#+id/cardNumber4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="#+id/cardNumber3"
android:layout_marginRight="50dp"
android:layout_marginTop="100dp" >
<include layout="#layout/card" />
</FrameLayout>
</RelativeLayout>
here is the Java code for the single child:
public class Card implements OnClickListener {
private int _resId;
private Context _context;
private ImageView firstImage, secondImage;
private boolean isFirst;
public Card(Context context, FrameLayout parent) {
_context = context;
firstImage = (ImageView) parent.findViewById(R.id.firstImage);
secondImage = (ImageView) parent.findViewById(R.id.secondImage);
}
public void setupCards(int resId, boolean hasBackSide) {
_resId = resId;
Bitmap temp = BitmapFactory.decodeResource(_context.getResources(),
_resId);
firstImage.setImageBitmap(temp);
if (hasBackSide) {
temp = BitmapFactory.decodeResource(_context.getResources(),
R.drawable.back);
}
secondImage.setImageBitmap(temp);
isFirst = true;
secondImage.setVisibility(View.GONE);
}
// MORE IMPLEMENTATION
}
this is my main activity Java code:
public class FaceUpActivity extends Activity {
FrameLayout firstCard, secondCard, thirdCard, forthCard;
Card cardNumber1, cardNumber2, cardNumber3, cardNumber4;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
initUI();
}
private void initUI() {
firstCard = (FrameLayout) findViewById(R.id.cardNumber1);
secondCard = (FrameLayout) findViewById(R.id.cardNumber2);
thirdCard = (FrameLayout) findViewById(R.id.cardNumber3);
forthCard = (FrameLayout) findViewById(R.id.cardNumber4);
cardNumber1 = new Card(this, firstCard);
cardNumber2 = new Card(this, secondCard);
cardNumber3 = new Card(this, thirdCard);
cardNumber4 = new Card(this, forthCard);
cardNumber1.setupCards(R.drawable.c2, true);
cardNumber2.setupCards(R.drawable.d0, true);
cardNumber3.setupCards(R.drawable.h5, true);
cardNumber4.setupCards(R.drawable.sj, true);
firstCard.setOnTouchListener(dragMe);
secondCard.setOnTouchListener(dragMe);
thirdCard.setOnTouchListener(dragMe);
forthCard.setOnTouchListener(dragMe);
}
OnTouchListener dragMe = new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
FrameLayout.LayoutParams params = (LayoutParams) v
.getLayoutParams();
int maxWidth = getWindowManager().getDefaultDisplay().getWidth();
int maxHeight = getWindowManager().getDefaultDisplay().getHeight();
int topMargin, leftMargin;
int cond = v.getId();
if (cond == R.id.cardNumber1 || cond == R.id.cardNumber2
|| cond == R.id.cardNumber3 || cond == R.id.cardNumber4) {
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
topMargin = (int) event.getRawY() - (v.getHeight());
leftMargin = (int) event.getRawX() - (v.getWidth()) / 2;
if (topMargin < 0) {
params.topMargin = 0;
} else if (topMargin > maxHeight) {
params.topMargin = maxHeight - v.getHeight();
} else {
params.topMargin = topMargin;
}
if (leftMargin < 0) {
params.leftMargin = 0;
} else if (leftMargin > maxWidth) {
params.leftMargin = maxWidth - (v.getWidth() / 2);
} else {
params.leftMargin = leftMargin;
}
v.setLayoutParams(params);
break;
case MotionEvent.ACTION_MOVE:
topMargin = (int) event.getRawY() - (v.getHeight());
leftMargin = (int) event.getRawX() - (v.getWidth()) / 2;
if (topMargin < 0) {
params.topMargin = 0;
} else if (topMargin > maxHeight) {
params.topMargin = maxHeight - v.getHeight();
} else {
params.topMargin = topMargin;
}
if (leftMargin < 0) {
params.leftMargin = 0;
} else if (leftMargin > maxWidth) {
params.leftMargin = maxWidth - (v.getWidth() / 2);
} else {
params.leftMargin = leftMargin;
}
v.setLayoutParams(params);
break;
}
}
return true;
}
};
}
Why your D&D is not working:
D&D is not working because your Card (that useses the internal FrameLayout) is implementing the onClick event that "eat" the d&d event.
Solutions are two:
you can have 2 different areas, one for the click event (the biggest part of the card), one for the d&d event (the bottom-left edge of the card). You can see a live example in the Android Music player that implements this solution.
Otherwise you can handle the two events at the same time:
click == down+up in the same time (under 100ms) in the same x/y location
dd == down+up in different times ( > 50/100ms)
I think there are a couple of potential problems:
Are you sure you're getting the correct IDs in your onTouch()? (since the touch listener is only used with your card views, you propably can remove the if checking for the IDs)
You are using a FrameLayout - so use the x and y position instead of margins edit: my bad, you're using RelativeLayout, so the margins are kind of right. Though, I'd use a FrameLayout instead
the API says you need to return true in onTouch() if you consumed the event, false otherwise (you're returning true when you didn't move the cards and nothing when you did)
Related
I have a LinearLayout which is centered on the screen. It has a width less than the screen width. There are two buttons: Right-Arrow and Left-Arrow.
When the user presses the relevant button, the layout should increase its width from the relevant side. The other side should keep its position there.
Right now setting the width increases the layout from both sides equally. The layout needs to be initially centered and it has to expand from either side by user's input. (Use case is to find the width of relevant part of an image whose right and left sides have unequal borders, so the user has to mark them using my technique).
I am using following to increase width but it has the behaviour described above.
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams)
llCropOverlay.getLayoutParams();
params.width = params.width + 1;
PS: This functionality was implemented in Tasker app since its early days; so it is possible.
EDIT:
Here is the layout.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:gravity="top"
android:layout_gravity="top"
android:id="#+id/iv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="visible" />
<LinearLayout
android:id="#+id/llRightLeft"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
<Button
android:id="#+id/bLeft"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="LEFT" />
<Button
android:id="#+id/bRight"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="RIGHT" />
</LinearLayout>
<LinearLayout
android:layout_gravity="center_horizontal"
android:id="#+id/llCropOverlay"
android:layout_width="match_parent"
android:layout_height="70dp"
android:background="#color/colorCropOverlay"
android:orientation="vertical" />
</FrameLayout>
</LinearLayout>
The last LinearLayout (llCropOverlay) should be resized. Note that I am programatically changing the width to 300 before using resizing the buttons so I can test if the buttons are working.
I have found an almost perfect solution (there is sometimes a problem with one pixel which is annoying - any suggestions will be appreciated).
For this, we need some variables set up. Firstly, the LinearLayout called llCropOverlay must be found and identified.
Here is its xml:
<LinearLayout
android:layout_gravity="center_horizontal"
android:id="#+id/llCropOverlay"
android:layout_width="200dp"
android:layout_height="150dp"
android:background="#color/colorCropOverlay"
android:orientation="vertical" />
Now before allowing user to interact we need to find the original position of the llCropOverlay. So use this in OnCreate():
llCropOverlay.post(new Runnable() {
#Override
public void run() {
orgX = llCropOverlay.getX();
}
});
Now set up all the buttons and set a setOnTouchListener() on these buttons. Then when the listener is called, pass the touched button in the following method. Use a Handler and postDelayed() to keep calling this method till the button is pressed. Or call it once to resize by one pixel row/column.
void handleTouchOrClick(View view) {
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams)
llCropOverlay.getLayoutParams();
switch (view.getId()) {
case R.id.bUp:
params.height = params.height - 1;
break;
case R.id.bDown:
params.height = params.height + 1;
break;
case R.id.bRight:
params.width = params.width + 1;
llCropOverlay.post(new Runnable() {
#Override
public void run() {
llCropOverlay.setX(orgX);
}
});
break;
case R.id.bRightContract:
params.width = params.width - 1;
llCropOverlay.post(new Runnable() {
#Override
public void run() {
llCropOverlay.setX(orgX);
}
});
break;
case R.id.bLeft:
params.width = params.width + 1;
orgX--;
llCropOverlay.post(new Runnable() {
#Override
public void run() {
llCropOverlay.setX(orgX);
}
});
break;
case R.id.bLeftContract:
params.width = params.width - 1;
orgX++;
llCropOverlay.post(new Runnable() {
#Override
public void run() {
llCropOverlay.setX(orgX);
}
});
break;
}
llCropOverlay.setLayoutParams(params);
}
Now here's how we actually resize the image:
For ease of users I am cropping it in two steps.
Crop from sides:
ViewGroup.MarginLayoutParams params =
(ViewGroup.MarginLayoutParams) llCropOverlay.getLayoutParams();
float eventX = params.width;
float eventY = 0;
float[] eventXY = new float[]{eventX, eventY};
Matrix invertMatrix = new Matrix();
imageView.getImageMatrix().invert(invertMatrix);
invertMatrix.mapPoints(eventXY);
int x = Integer.valueOf((int) eventXY[0]);
int y = Integer.valueOf((int) eventXY[1]);
int height = params.height;
while (height * 3 > originalBitmap.getHeight()) {
height = height - 10;
}
croppedBitmapByWidth = Bitmap.createBitmap(originalBitmap, (int) orgX, 0,
x, height);
imageView.setImageBitmap(croppedBitmapByWidth);
crop from bottom:
float eventX2 = 0;
float eventY2 = params.height;
float[] eventXY2 = new float[]{eventX2, eventY2};
Matrix invertMatrix2 = new Matrix();
imageView.getImageMatrix().invert(invertMatrix2);
invertMatrix2.mapPoints(eventXY2);
int x2 = Integer.valueOf((int) eventXY2[0]);
int y2 = Integer.valueOf((int) eventXY2[1]);
croppedBitmapByHeight = Bitmap.createBitmap(croppedBitmapByWidth, 0, 0,
croppedBitmapByWidth.getWidth(), y2);
imageView.setImageBitmap(croppedBitmapByHeight);
i have some problem with programmatically layoyt resize. I have layout
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/black"
android:visibility="visible"
android:id="#+id/lb_lobby_center_layout" >
<include layout="#layout/lb_top_banner"
android:layout_height="115dp"
android:layout_width="match_parent"
android:layout_below="#+id/lb_top_menu_parent"
/>
<include layout="#layout/lb_top_menu"
android:layout_height="65dp"
android:layout_width="match_parent"
/>
<include layout="#layout/lb_ctg_game"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_below="#+id/lb_top_banner_ll_parent"/>
</RelativeLayout>
In onTouch() method of lb_ctg_game i movie layout lb_top_banner up on axis Y.
layout lb_ctg_game must take this free place. I can change topMargin of lb_ctg_game, but I can't resize it's height. I have free place in the bottom.
private void replaceView(int deltaY)
{
RelativeLayout.LayoutParams bannersParam = (RelativeLayout.LayoutParams) disappearView.getLayoutParams();
RelativeLayout.LayoutParams gameContainerParams = (RelativeLayout.LayoutParams) gameContainer.getLayoutParams();
int top =0, bottom = 0;
if (isGoUp)
{
top = disappearView.getTop();
bottom = disappearView.getBottom();
if ((bottom - deltaY) > topBorder)
{
bannersParam.topMargin = top - deltaY;
bannersParam.bottomMargin = bottom - deltaY;
//disappearView.setLayoutParams(params2);
disappearView.layout(disappearView.getLeft(),bannersParam.topMargin,disappearView.getRight(),bannersParam.bottomMargin);
//disappearView.requestLayout();
gameContainerParams.topMargin =bannersParam.bottomMargin;
int yyy = gameContainer.getBottom() + deltaY;
//gameContainer.setLayoutParams(listParams);
gameContainer.layout(gameContainer.getLeft(),gameContainerParams.topMargin,gameContainer.getRight(),yyy);//gameContainer.getBottom()
//layout(getLeft(),getTop(),getRight(),yyy);//getBottom()
gameContainer.forceLayout();
//gameContainer.requestLayout();
}
else
{
bannersParam.bottomMargin = topBorder -10;
bannersParam.topMargin= bannersParam.bottomMargin - disappearView.getHeight();
disappearView.layout(disappearView.getLeft(),bannersParam.topMargin,disappearView.getRight(),bannersParam.bottomMargin);
//disappearView.requestLayout();
gameContainerParams.topMargin =topBorder;
int yyy = gameContainer.getBottom() + disappearView.getHeight();
//yyy = listParams.topMargin+yyy;
//gameContainer.setLayoutParams(gameContainerParams);
int th = gameContainer.getHeight();
gameContainer.layout(gameContainer.getLeft(),gameContainerParams.topMargin,gameContainer.getRight(),yyy);//
//layout(getLeft(),getTop(),getRight(),yyy);//getBottom()
gameContainer.forceLayout();
//gameContainer.requestLayout();
//this.forceLayout();
}
}
else
{
int d = getFirstVisiblePosition();
if (getFirstVisiblePosition() != 0)
return;
top = disappearView.getTop();
bottom = disappearView.getBottom();
if ((top + deltaY)<topBorder)
{
bannersParam.topMargin = top + deltaY;
bannersParam.bottomMargin = bottom + deltaY;
//disappearView.setLayoutParams(params2);
disappearView.layout(disappearView.getLeft(),bannersParam.topMargin,disappearView.getRight(),bannersParam.bottomMargin);
disappearView.forceLayout();
gameContainerParams.topMargin =bannersParam.bottomMargin;
gameContainer.layout(gameContainer.getLeft(), gameContainerParams.topMargin, gameContainer.getRight(), gameContainer.getBottom());
//layout(getLeft(),listParams.topMargin,getRight(),getBottom());
gameContainer.forceLayout();
// gameContainer.invalidate();
}
else
{
bannersParam.topMargin= initionalY;
bannersParam.bottomMargin = bannersParam.topMargin + disappearView.getHeight();
disappearView.layout(disappearView.getLeft(),bannersParam.topMargin,disappearView.getRight(),bannersParam.bottomMargin);
disappearView.forceLayout();
gameContainerParams.topMargin = bannersParam.bottomMargin;
int yyy = gameContainer.getBottom();
gameContainer.layout(gameContainer.getLeft(), gameContainerParams.topMargin, gameContainer.getRight(), gameContainer.getBottom());
//layout(getLeft(),listParams.topMargin,getRight(),getBottom());
gameContainer.forceLayout();
// gameContainer.invalidate();
}
}
}
I have a button with a list view underneath it. The XML looks like this:
<LinearLayout
android:id="#+id/linearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="#+id/button1"
android:text="#string/button1_text"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<ListView
android:id="#+id/listview1"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
Pressing the button shows or hides a listview underneath it, using this code:
private OnClickListener expandOnClickListener = new OnClickListener() {
#Override
public void onClick(View v) {
if (listview1.getVisibility() == View.VISIBLE) {
listview1.setVisibility(View.GONE);
} else {
listview1.setVisibility(View.VISIBLE);
}
}
};
The result looks like this:
Now, I have two of these button/listview combinations.
If the are BOTH open, they should share the space on the screen.
If one or the other is open, they should take up as much of the screen as they can, without pushing the button off the screen.
I've tried using weights. I've tried manipulating the height of the linear layout to either 'wrap content' or a specifically calculated pixel value. I've tried to debug through it. It appears to hit all the correct places in the code, but the UI behaves erratically. Any ideas on how I could do this?
After writing up my entire question, I decided to try a couple of things, and amazingly it works. It's a combination of setting the weights and the heights.
XML:
<LinearLayout
android:id="#+id/llWrapper"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:id="#+id/llOne"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<Button
android:id="#+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button1" />
<ListView
android:id="#+id/listview1"
style="#style/text.body"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:id="#+id/llTwo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<Button
android:id="#+id/button2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button2" />
<ListView
android:id="#+id/listview2"
style="#style/text.body"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
Java Code:
private OnClickListener expandOnClickListener = new OnClickListener() {
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button1:
toggleONEVisibility();
break;
case R.id.button2:
toggleTWOVisibility();
break;
}
}
};
private void toggleONEVisibility() {
LinearLayout.LayoutParams layoutParam2 = (LinearLayout.LayoutParams)linearLayout2.getLayoutParams();
LinearLayout.LayoutParams layoutParam1 = (LinearLayout.LayoutParams)linearLayout1.getLayoutParams();
// if ONE is visible
// if TWO is visible
// set TWO to 100%
// set ONE to GONE
// else ONE is NOT visible
// if TWO is visible
// set ONE to 50%
// set TWO to 50%
// else TWO is NOT visible
// set ONE to 100%
// set ONE to visible
if (listview1.getVisibility() == View.VISIBLE) {
listview1.setVisibility(View.GONE);
layoutParam1.weight = 0f;
layoutParam1.height = LayoutParams.WRAP_CONTENT;
if (listview2.getVisibility() == View.VISIBLE) {
layoutParam2.weight = 1f;
layoutParam2.height = 0;
}
} else {
listview1.setVisibility(View.VISIBLE);
if (listview2.getVisibility() == View.VISIBLE) {
layoutParam1.weight = 50f;
layoutParam1.height = 0;
layoutParam2.weight = 50f;
layoutParam2.height = 0;
} else {
layoutParam1.weight = 1f;
layoutParam1.height = 0;
layoutParam2.weight = 0f;
layoutParam2.height = LayoutParams.WRAP_CONTENT;
}
}
linearLayout1.setLayoutParams(layoutParam1);
linearLayout2.setLayoutParams(layoutParam2);
}
private void toggleTWOVisibility() {
LinearLayout.LayoutParams layoutParam2 = (LinearLayout.LayoutParams)linearLayout2.getLayoutParams();
LinearLayout.LayoutParams layoutParam1 = (LinearLayout.LayoutParams)linearLayout1.getLayoutParams();
// if TWO is visible
// if ONE is visible
// set ONE to 100%
// set TWO to GONE
// else TWO is NOT visible
// if ONE is visible
// set ONE to 50%
// set TWO to 50%
// else ONE is NOT visible
// set TWO to 100%
// set TWO to visible
if (listview2.getVisibility() == View.VISIBLE) {
listview2.setVisibility(View.GONE);
layoutParam2.weight = 0f;
layoutParam2.height = LayoutParams.WRAP_CONTENT;
if (listview1.getVisibility() == View.VISIBLE) {
layoutParam1.weight = 1f;
layoutParam1.height = 0;
}
} else {
listview2.setVisibility(View.VISIBLE);
if (listview1.getVisibility() == View.VISIBLE) {
layoutParam1.weight = 50f;
layoutParam1.height = 0;
layoutParam2.weight = 50f;
layoutParam2.height = 0;
} else {
layoutParam1.height = LayoutParams.WRAP_CONTENT;
layoutParam1.weight = 0f;
layoutParam2.weight = 1f;
layoutParam2.height = 0;
}
}
linearLayout1.setLayoutParams(layoutParam1);
linearLayout2.setLayoutParams(layoutParam2);
}
I am trying to create a stack of cards dynamically by using a RelativeLayout and setting the ALIGN_PARENT_BOTTOM rule and the bottomMargin. But the cards keep getting drawn over each other disregarding the margin. But they draw properly when I use ALIGN_PARENT_TOP and topMargin.
activity_single_player_game.xml (Code creating RelativeLayout)
<!-- other code -->
<RelativeLayout
android:id="#+id/frame_card_stack"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="bottom" >
<ImageView
android:id="#+id/image_hand_value"
android:layout_width="40dip"
android:layout_height="20dip"
android:layout_alignParentBottom="true"
android:layout_marginBottom="20dip" />
<TextView
android:id="#+id/text_hand_value"
android:layout_width="40dip"
android:layout_height="20dip"
android:gravity="center"
android:layout_alignParentBottom="true"
android:background="#88000000" />
</RelativeLayout>
<RelativeLayout
android:id="#+id/frame_card_stack_split"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:gravity="bottom" >
<ImageView
android:id="#+id/image_hand_value_split"
android:layout_width="40dip"
android:layout_height="20dip"
android:layout_alignParentBottom="true" />
<TextView
android:id="#+id/text_hand_value_split"
android:layout_width="40dip"
android:layout_height="20dip"
android:gravity="center"
android:layout_alignParentBottom="true"
android:background="#88000000" />
</RelativeLayout>
<!-- other code -->
SinglePlayerGameActivity.java (Code creating the stack of cards)
RelativeLayout playerView;
RelativeLayout playerViewSplit;
#Override
protected void OnCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_single_player_game);
playerView = (RelativeLayout) findViewById(R.id.frame_card_stack);
playerViewSplit = (RelativeLayout) findViewById(R.id.frame_card_stack_split);
}
public ImageView getCardImage(BJCard card, int offset, boolean playerCard) {
ImageView cardImage = new ImageView(this);
cardImage.setImageResource(BJUtility.drawableIdForCard(card));
cardImage.setBackgroundColor(0x40000000);
if (playerCard) {
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
params.bottomMargin = dip(20 * offset);
cardImage.setLayoutParams(params);
} else {
LayoutParams params = new LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
cardImage.setLayoutParams(params);
}
return cardImage;
}
public void populatePlayer() {
BJPlayerBox box = MenuActivity.bjmc.playerBoxes.get(MenuActivity.bjmc.activePlayerBox);
BJCardDeck deck = box.cardDecks.get(box.activeDeckIndex);
for (int i = 0; i < deck.cards.size(); i++) {
BJCard card = deck.cards.get(i);
playerView.addView(getCardImage(card, i, true), playerView.getChildCount() - 2);
}
updatePlayerSumView(deck, BEGIN, box.activeDeckIndex);
}
public void updatePlayer(int flag) {
BJPlayerBox box = MenuActivity.bjmc.playerBoxes.get(MenuActivity.bjmc.activePlayerBox);
switch (flag) {
case HIT:
BJCardDeck deck = box.cardDecks.get(box.activeDeckIndex);
for (int i = playerView.getChildCount() - 2; i < deck.cards.size(); i++) {
BJCard card = deck.cards.get(i);
playerView.addView(getCardImage(card, i, true), playerView.getChildCount() - 2);
}
updatePlayerSumView(deck, flag, box.activeDeckIndex);
break;
case SPLIT:
playerViewSplit.setVisibility(android.view.View.VISIBLE);
ImageView splitCardView = (ImageView) playerView.getChildAt(playerView.getChildCount() - 2);
playerView.removeView(splitCardView);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
params.bottomMargin = dip(0);
playerViewSplit.addView(splitCardView, playerViewSplit.getChildCount() - 2);
splitCardView.setLayoutParams(params);
// update first deck
BJCardDeck splitDeck = box.cardDecks.get(0);
BJCard card = splitDeck.cards.get(1);
playerView.addView(getCardImage(card, 1, true), playerView.getChildCount() - 2);
updatePlayerSumView(splitDeck, SPLIT, 0);
// update split deck
splitDeck = box.cardDecks.get(1);
card = splitDeck.cards.get(1);
playerViewSplit.addView(getCardImage(card, 1, true), playerViewSplit.getChildCount() - 2);
updatePlayerSumView(splitDeck, SPLIT, 1);
break;
case SURRENDER:
updatePlayerSumView(box.activeCardDeck(), flag, box.activeDeckIndex);
}
}
public void updatePlayerSumView(BJCardDeck deck, int flag, int splitIndex) {
ImageView iv;
TextView tv;
if (splitIndex == 0) {
iv = (ImageView) findViewById(R.id.image_hand_value);
tv = (TextView) findViewById(R.id.text_hand_value);
} else {
iv = (ImageView) findViewById(R.id.image_hand_value_split);
tv = (TextView) findViewById(R.id.text_hand_value_split);
}
if (flag == SURRENDER) {
tv.setText(null);
iv.setImageResource(R.drawable.flag);
return;
}
if (flag != SPLIT && BJUtility.isBlackjack(deck)) {
iv.setImageResource(R.drawable.crown);
} else {
int[] playerSum = BJUtility.currentCardHandTotal(deck.cards);
if (playerSum[0] > 21) {
tv.setText(null);
iv.setImageResource(R.drawable.bust);
} else {
if (playerSum.length == 1) {
tv.setText(Integer.toString(playerSum[0]));
tv.setTextColor(getResources().getColor(R.color.orangish_yellow));
} else {
// TODO: if deckState = active, show both, else, show one
tv.setText(playerSum[1] + "/" + playerSum[0]);
tv.setTextColor(getResources().getColor(R.color.orangish_yellow));
}
}
}
}
Here are some screenshots-
This is what I get when I use ALIGN_PARENT_TOP and topMargin. I want exactly this, except that the circled cards should be down with the text.
This is what I get when I use ALIGN_PARENT_BOTTOM and bottomMargin. Here the cards are in the correct position as a group, but they are all drawn completely over each other, so I can see only one.
What is your playerView??
If it is a RelativeLayout and the android:layout_height="wrap_content" then android:layout_marginBottom does not work.
Since setting android:paddingBottom="" to the playerView is not an option for you, you can try setting the android:layout_marginTop for the previous child views.
Something like, adding android:layout_marginTop to the 1st card, while adding the 2nd card.
I am trying to add views to LinearLayout dynamically as much as it possible (depending on screen width).
I do this before the LinearLayout displays on screen.
My LinearLayout:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center"
android:background="#666"/>
My view to display in LinearLayout:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:background="#999">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:src="#drawable/no_photo"/>
</FrameLayout>
I add views to layout:
int allItems = 50;
int currentItem = 0;
while(currentItem < allItems)
{
FrameLayout view = (FrameLayout) inflater.inflate(R.layout.fl, null);
linearLayout.addView(view);
if (linearLayout.getMeasuredWidth() >= this.getWidth())
{
linearLayout.removeView(view);
break;
}
}
but linearLayout.getMeasuredWidth() and this.getWidth() is 0;
I know, that i must use View.measure method to calculate view size before it became visible, but i don't know where and how it use.
Edit your code as below :
Display display = getWindowManager().getDefaultDisplay();
int maxWidth = display.getWidth();
int widthSoFar=0;
int allItems = 50;
int currentItem = 0;
while(currentItem < allItems) {
FrameLayout view = (FrameLayout) inflater.inflate(R.layout.fl, null);
linearLayout.addView(view);
view .measure(0, 0);
widthSoFar = widthSoFar + view.getMeasuredWidth();
if (widthSoFar >= maxWidth) {
linearLayout.removeView(view);
break;
}
}
Hope this helps you