Move ImageView relatively to another imageView's position- Android Studio - android

I'm trying to make an ImageView follow another ImageView, by changing it's coordinates. My movement method is that:
public void move(double zx, double zy) {
if (zx < a.getLeft()) {
if (a.getLeft() - zx > 0) {
a.setLeft(a.getLeft() - 1);
} else
a.setLeft(a.getLeft()+1);
}
if (zx > a.getLeft()) {
if (a.getLeft() - zx > 0) {
a.setLeft(a.getLeft() - 1);
} else
a.setLeft(a.getLeft() - 1);
}
if (zy > a.getTop()) {
if (a.getTop() - zy > 0) {
a.setTop(a.getTop() - 1);
} else
a.setTop(a.getTop() + 1);;
}
if (zy < a.getTop()) {
if (a.getTop() - zy > 0) {
a.setTop(a.getTop() - 1);
} else
a.setTop(a.getTop() + 1);
}
}
OnCreate:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fase);
a = (ImageView)findViewById(R.id.a);
b = (ImageView)findViewById(R.id.b);
move(b.getLeft(), b.getTop());
}
"a" and "b" are the ImageViews, and a should follow b. I declared both ImageViews correctly, and the method should work. Instead of it, the ImageView "a" keep in the same position since the application starts. What is wrong? Is the method move declared at the wrong place (onCreate) ? I also have tried to just set the vertical position of "a" in another part of the screen, for testing if it would work. But it didn't (and according to the logCat it's vertical position had changed). The tutorials I found about moving images are based on dragging them, but I haven't still found anything about another kind of movement, like this.
There is my layout (activity_fase.xml) :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context="thegame.app.Fase"
android:background="#drawable/seapaint">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/b"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:src="#drawable/b"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/a"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:src="#drawable/a"
android:focusable="true"
android:clickable="false"
android:layout_marginBottom="79dp" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/imageView2"
android:layout_above="#+id/b"
android:layout_alignLeft="#+id/a"
android:layout_alignStart="#+id/key"
android:layout_marginBottom="67dp"
android:src="#drawable/key"
android:layout_marginLeft="50dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="Small Text"
android:id="#+id/points"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
I'm new on android developing, and I don't know the difference between relative layout and linear layout.

PROBLEM SOLVED
It's possible to change an ImageView's position for any region of the screen by setting a relativeLayout by code, and adding to it's parameters the leftMargin and the topMargin. Example:
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(80,80);
// 80 is just a number of my choice. There are many possibilities
params.leftMargin = 200;
params.topMargin = 400;
a.setLayoutParams(params);
Now the imageView's coordinates are (200,400). A successive change can be done. If you creat a timer that is called each 0.05 seconds and a task that adds 1 to the leftMargin and topMargin, the image's position will be successfully changed.

Related

Asymmetric RelativeLayout behavior in Android

The following two layout files produce different results:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center">
<View
android:id="#+id/box"
android:background="#ff0000"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_alignParentLeft="true"
android:layout_toLeftOf="#+id/next_box" />
<View
android:id="#+id/next_box"
android:background="#0000ff"
android:layout_width="60dp"
android:layout_alignParentRight="true"
android:layout_height="30dp"
/>
</RelativeLayout>
</LinearLayout>
Result:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center">
<View
android:id="#+id/box"
android:background="#ff0000"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_alignParentLeft="true"
/>
<View
android:id="#+id/next_box"
android:background="#0000ff"
android:layout_width="60dp"
android:layout_alignParentRight="true"
android:layout_height="30dp"
android:layout_toRightOf="#+id/box"
/>
</RelativeLayout>
</LinearLayout>
Result:
Both layouts are trying to describe the same constraints. Namely, the red rectangle should touch the left edge of the parent, the blue rectangle should touch the right edge of the parent, and they should appear next to each other horizontally. The only difference is whether you specify the "next to" constraint on the red rectangle or the blue rectangle. I figured out the reason which has to do with the measure resolution order generated by forming a dependency graph of the constraints, but I only figured it out through reading RelativeLayout's source code, and I couldn't find any documentation / notes regarding this behavior. Since RelativeLayout must be a commonly used layout component, is there a more intuitive explanation for this behavior, or is there some part of documentation that I am missing?
Although both seem to describe the same constraints, they actually don't. The difference is that one says, red must sit next to blue, while the other says blue must sit next to red. One means that where ever red goes blue must follow, the other says, where ever blue goes red must follow, and they both want to go to different places.
In the first instance, red box depends on the blue box, so the blue box gets constructed first. The blue box has a width of 60dp, so a 60dp blue box is constructed first and aligned right. Then comes the red box, which has a constraint to sit next to the blue box. Width 0 is ignore because it needs to sit next to 60dp blue and align left.
In the second instance, blue box depends on the red box, so the red box gets constructed first. The red box says it wants 0dp and align left, so it can't be seen. Then comes the blue box which needs to sit next to invisible red and align right, thus occupying the entire space, its width ignored.
Hope this makes sense :)
All this parameters defined in:
android.widget.RelativeLayout
private void applyHorizontalSizeRules(LayoutParams childParams, int myWidth, int[] rules) {
RelativeLayout.LayoutParams anchorParams;
// VALUE_NOT_SET indicates a "soft requirement" in that direction. For example:
// left=10, right=VALUE_NOT_SET means the view must start at 10, but can go as far as it
// wants to the right
// left=VALUE_NOT_SET, right=10 means the view must end at 10, but can go as far as it
// wants to the left
// left=10, right=20 means the left and right ends are both fixed
childParams.mLeft = VALUE_NOT_SET;
childParams.mRight = VALUE_NOT_SET;
anchorParams = getRelatedViewParams(rules, LEFT_OF);
if (anchorParams != null) {
childParams.mRight = anchorParams.mLeft - (anchorParams.leftMargin +
childParams.rightMargin);
} else if (childParams.alignWithParent && rules[LEFT_OF] != 0) {
if (myWidth >= 0) {
childParams.mRight = myWidth - mPaddingRight - childParams.rightMargin;
}
}
anchorParams = getRelatedViewParams(rules, RIGHT_OF);
if (anchorParams != null) {
childParams.mLeft = anchorParams.mRight + (anchorParams.rightMargin +
childParams.leftMargin);
} else if (childParams.alignWithParent && rules[RIGHT_OF] != 0) {
childParams.mLeft = mPaddingLeft + childParams.leftMargin;
}
anchorParams = getRelatedViewParams(rules, ALIGN_LEFT);
if (anchorParams != null) {
childParams.mLeft = anchorParams.mLeft + childParams.leftMargin;
} else if (childParams.alignWithParent && rules[ALIGN_LEFT] != 0) {
childParams.mLeft = mPaddingLeft + childParams.leftMargin;
}
anchorParams = getRelatedViewParams(rules, ALIGN_RIGHT);
if (anchorParams != null) {
childParams.mRight = anchorParams.mRight - childParams.rightMargin;
} else if (childParams.alignWithParent && rules[ALIGN_RIGHT] != 0) {
if (myWidth >= 0) {
childParams.mRight = myWidth - mPaddingRight - childParams.rightMargin;
}
}
if (0 != rules[ALIGN_PARENT_LEFT]) {
childParams.mLeft = mPaddingLeft + childParams.leftMargin;
}
if (0 != rules[ALIGN_PARENT_RIGHT]) {
if (myWidth >= 0) {
childParams.mRight = myWidth - mPaddingRight - childParams.rightMargin;
}
}
}
The view left and right edges ( childParams.mLeft, childParams.mRight) calculations based on anchor view parameters (anchorParams). From this code childParams.mRight edge of the view defined by LEFT_OF (android:layout_toLeftOf) can be recalculated by ALIGN_RIGHT (android:layout_alignRight) or ALIGN_PARENT_RIGHT (android:layout_alignParentRight). Here is explanation why 0-width red view become more than 0.
<View
android:id="#+id/box"
android:background="#ff0000"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_alignParentLeft="true"
android:layout_toLeftOf="#+id/next_box"/>
Right edge of this view defined by LEFT_OF:
childParams.mRight = anchorParams.mLeft - (anchorParams.leftMargin +
childParams.rightMargin);
In this case anchor view is:
<View
android:id="#+id/next_box"
android:background="#0000ff"
android:layout_width="60dp"
android:layout_alignParentRight="true"
android:layout_height="30dp"
/>
the left edge of this view 60dp from the right side of the screen margings not defined => childParams.mRight = screen_width - 60dp
Left edge of this view defined by ALIGN_PARENT_LEFT:
childParams.mLeft = mPaddingLeft + childParams.leftMargin;
the left edge of this view left edge of anchor view is 0 because android:layout_alignParentLeft="true" and margins not defined => childParams.mLeft = 0
the same calculation can be done for the second example:
childParams.mRight = screen_width
childParams.mLeft = 0

In Android get center of Relative Layout on API 10

I'm trying to find the center coordinates of a RelativeLayout that for the moment, is empty. I need to find the center before I can put anything into the Relative Layout. The Relative Layout is not the whole screen, so I can't use metrics to find the screen dimensions. Since my minimum API is 10, I can't use rLayout.getX() or rLayout.getY(). So what I've tried is:
int xScreenInt = gBoard_RL.getWidth()/2;
int yScreenInt = gBoard_RL.getHeight()/2;
int xInt = gBoard_RL.getLeft() + xScreenInt;
int yInt = gBoard_RL.getTop() + yScreenInt;
and all I get is 0,0. Does anyone have an any ideas how I can get this done? Here's my layout and the Activity so far:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/gb1_root_RL"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
tools:context=".GB1" >
<RelativeLayout
android:id="#+id/gb1_topInfo_RL"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:background="#drawable/blu_grade_bg"
android:orientation="vertical"
android:paddingBottom="15dp" >
<TextView
android:id="#+id/gb1_scValue_TV"
style="#style/mainScoreValueStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="#+id/gb1_score_TV"
android:layout_marginLeft="10dp" />
<TextView
android:id="#+id/gb1_timeValue_TV"
style="#style/mainTimeValueStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="#+id/gb1_time_TV"
android:layout_marginRight="10dp" />
</RelativeLayout>
<RelativeLayout
android:id="#+id/gb1_gf_RL"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/gb1_topInfo_RL"
android:padding="10dp" >
</RelativeLayout>
the Relative Layout I need to find the center of is: android:id="#+id/gb1_gf_RL"
public class GB1 extends Activity {
TextView GScore_TV;
RelativeLayout gBoard_RL;
int xScreenInt, yScreenInt, xInt, yInt;
String xStr, yStr;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
overridePendingTransition(R.anim.cutin, R.anim.cutout);
setContentView(R.layout.gb_layout);
GScore_TV = (TextView) findViewById(R.id.G1_scoreValue_TV);
gBoard_RL = (RelativeLayout) findViewById(R.id.gb1_gf_RL);
gBoard_RL.setBackgroundColor(Color.MAGENTA);
xScreenInt = gBoard_RL.getWidth()/2;
yScreenInt = gBoard_RL.getHeight()/2;
xInt = gBoard_RL.getLeft() + xScreenInt;
yInt = gBoard_RL.getTop() + yScreenInt;
xStr = String.valueOf(xInt);
yStr = String.valueOf(yInt);
GScore_TV.setText(xStr + ", " + yStr);
}
}
Try putting your code in a onGlobalLayout listener:
myRelativelayout.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
this.layout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
//Your code here
}
});
EDIT:
Since, as #xorgate pointed out, the layout isnt drawn yet in the onCreate method. The onGlobalLayout method will be called when the layout is drawn and calculations such as yours should be done in there.
onCreate is called before a layout pass is done. All Views will have no size yet.
Try setting a global layout listener, and do the positioning code there.

Spreading gracefully buttons horizontally across a Layout

This is my very first post at Stackoverflow. Before I make my question, I just want to say that this is a great resource of information and I find the community extremely helpful.
I hope to be able to share my Android development knowledge with everyone else as well.
I have been developing for Android for 6 months now and, although I have learned very much, I still greatly struggle when it comes to layout/design.
I have one layout.xml file that contains a Relative layout. Inside this layout, I have three buttons. I want those three buttons to have a certain width size that would grow or shrink depending on the device's screen size/density.
This is the xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/relativeLayout1123123213"
android:layout_width="fill_parent"
android:layout_height="#dimen/actionbar_height"
android:orientation="horizontal">
<Button
android:id="#+id/btnLogin"
android:layout_width="100dp"
android:layout_height="50dp"
android:background="#drawable/button"
android:drawableLeft="#drawable/balloon_overlay_close"
android:gravity="center"
android:text="Earned" />
<Button
android:id="#+id/btnLogin2"
android:layout_width="113dp"
android:layout_height="50dp"
android:layout_alignParentTop="true"
android:layout_toRightOf="#+id/btnLogin"
android:background="#drawable/button"
android:drawableLeft="#drawable/balloon_overlay_close"
android:gravity="center"
android:text="In Progress" />
<Button
android:id="#+id/btnLogin3"
android:layout_width="107dp"
android:layout_height="50dp"
android:layout_alignParentTop="true"
android:layout_toRightOf="#+id/btnLogin2"
android:background="#drawable/button"
android:drawableLeft="#drawable/balloon_overlay_close"
android:gravity="center"
android:text="Done" />
</RelativeLayout>
I hard coded the width values, considering that I have different text sizes in each button... so that should obviously affect the width as well...
My question is... is there any intelligent way to accomplish this? Maybe programatically, when I know the current device's screen size?
Thanks everyone!
Felipe
====================================================
UPDATED SECTION
Hey guys,
Thanks for your help so far.
I have added the LinearLayout and the weight as per recommendation, but I am still not exactly getting what I want. It's almost there, but not quite.
My new xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="#dimen/actionbar_height"
android:orientation="horizontal"
android:gravity="center" android:weightSum="1">
<Button
android:id="#+id/btnLogin"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="#drawable/button"
android:drawableLeft="#drawable/balloon_overlay_close"
android:gravity="center"
android:text="#string/bottonbar_earned"
android:layout_weight=".10"/>
<Button
android:id="#+id/btnLogin2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=".10"
android:background="#drawable/button"
android:drawableLeft="#drawable/balloon_overlay_close"
android:gravity="center"
android:text="#string/bottonbar_inprogress" />
<Button
android:id="#+id/btnLogin3"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="#drawable/button"
android:drawableLeft="#drawable/balloon_overlay_close"
android:gravity="center" android:text="#string/bottonbar_redeemed"
android:layout_weight=".90"/>
</LinearLayout>
This is the result link
Can you see the end of the right side? I don't think the weight is distributed like it should, although I set a .90 weight to the third button.
What do you guys think?
What you can do is use android:layout_weight attribute on buttons, but you need to place them into a LinearLayout. If you need to have RelativeLayout, then you can place the LinearLayout inside it.
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:weightSum="1.0" >
<Button
android:text="left"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight=".30" />
<Button
android:text="center"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight=".40" />
<Button
android:text="right"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight=".30" />
</LinearLayout>
If you could do it in xml itself, I wouldn't recommend doing it programmatically. You can add something like :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center" style="android:style/ButtonBar" >
<Button android:text="Ok" android:id="#+id/bookOkBtn"
android:layout_width="0dp" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_marginRight="10dp" />
<Button android:text="Return" android:id="#+id/bookReturnBtn"
android:layout_width="0dp" android:layout_height="wrap_content"
android:layout_weight="1"/>
</LinearLayout>
Making android:layout_width="0" & android:layout_weight=1 uses all the available space width wise.
If you want height-wise also, then specify dip in android:layout_height="100dip" and check your desired height.
If this also doesn't fit your needs and dynamic setting is only the solution, then have added Answer for that too.
UPDATED :
Have a look at this code :
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:orientation="horizontal" android:gravity="center"
android:layout_marginTop="15dp" style="android:style/ButtonBar">
<Button android:id="#+id/browseAddBtn" android:text="Add" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:layout_marginRight="10dp" />
<Button android:id="#+id/browseViewBtn" android:text="Edit" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:layout_marginRight="10dp" />
<Button android:id="#+id/browseDelBtn" android:text="Delete" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:layout_marginRight="10dp" />
<Button android:id="#+id/browseReturnBtn" android:text="Return" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" />
</LinearLayout>
RESULTS
Image shows results of above code and also on changing the layout_weight as mentioned in file respectively. My parent layout is also LinearLayout & has no padding or margins set.
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" android:orientation="vertical">
This sounds more like a case for a LinearLayout than a RelativeLayout. If you specify a LinearLayout as the parent with a total layout weight of 3 and have each of your Buttons specify a layout weight of 1 they should end up precisely as you desire on any screen.
I had same situation where I had to set sizes of buttons based on screen sizes and density. I calculate the size of buttons based on the actual space for the application I get.
I would suggest you to use LinearLAyout instead of RelativeLayout, but as you have some experience, you must be aware of the differences and ease of usage with Linear rather than Relative layouts.
In my XML I have root LinearLayout & 2 inner LinearLayout (row1 & row2). Each row has 3 butttons.
In my onCreate I get above 3 of them using findViewById.
Using the LayoutParams and the screen's size and densty, I calcualte the size of buttons and text sizes.
Algorithm :
Get Screen height & Width
Deduct the padding & margins you use
Deduct height of Title bar
Now, you have got your full available space. Divide it horizontally & vertically as you need
This will give you size of 1 button
Set the same size to all buttons
Based on buttons width & height & density figure out the text size
You can start up with this, if you need help I will be there. Feel free to ask.
UPDATED : CODE ADDED :-
These methods are added in a class named "Utility" and made static to access the methods in whole project easily :
public static ScreenInfo scrnInfo = new ScreenInfo();
public static void calculateChildSize(LinearLayout root, LinearLayout.LayoutParams row1Params, LinearLayout.LayoutParams row2Params, DisplayMetrics metrics) {
int height, width;
int childWidth, childHeight;
//gets screen dimensions
height = metrics.heightPixels; //480
width = metrics.widthPixels; //320
scrnInfo.setScreenHeight(height);
scrnInfo.setScreenWidth(width);
//Log.i("MY", "Actual Screen Height = " + height + " Width = " + width);
// Get height/width after deducting Padding of all 4 sides
height = height - (root.getPaddingBottom() + root.getPaddingTop()); // 480-70
width = width - (root.getPaddingLeft() + root.getPaddingRight()); // 320-70
//Log.i(TAG, "Actual Area after Padding W = " + width + " H = " + height);
int bottomMargin = row1Params.bottomMargin; //15
bottomMargin = (row1Params.bottomMargin %2) == 0 ? row1Params.bottomMargin : row1Params.bottomMargin+1;
// Actual Height/Width of child
childWidth = (int)(width);
childHeight = (int)(height /2) - (bottomMargin/2);
childHeight -= scrnInfo.getTitleBarHeight();
scrnInfo.setRowHeight(childHeight);
row1Params.height = childHeight;
row1Params.width = childWidth;
row1Params.bottomMargin = (bottomMargin/2);
row2Params.height = childHeight;
row2Params.width = childWidth;
row2Params.topMargin = (bottomMargin/2);
scrnInfo.setChild1LayoutParams(row1Params);
scrnInfo.setChild2LayoutParams(row2Params);
calcTileWidthHeight(childWidth);
calcTileTextSize();
//android.util.Log.i(TAG, "Child W = " + childWidth + " H = " + childHeight + " Tile W = " + scrnInfo.getTileWidth() + " Tile Text Size = " + getTileTextSize());
return;
}
public static void calcTileWidthHeight(int childWidth) {
int margin = 8;
scrnInfo.setTileWidth(((childWidth/3)-margin));
}
public static void findTitleBarHeight(Window win) {
Rect rect = new Rect();
win.getDecorView().getWindowVisibleDisplayFrame(rect);
int statusHeight = rect.top;
int contentViewTop = win.findViewById(Window.ID_ANDROID_CONTENT).getTop();
int titleHeight = contentViewTop - statusHeight;
scrnInfo.setTitleBarHeight(titleHeight); // SET TitleBarHeight
//Log.i(Utility.TAG, "titleHeight = " + titleHeight + " statusHeight = " + statusHeight + " contentViewTop = " + contentViewTop);
return;
}
public static void calcTileTextSize() {
// current is 11 on W = 75 => its small
int w = scrnInfo.getTileWidth();
float ts = 11f;
if (w >= 51 && w <= 70) // Port LDPI W - 54 H -98
ts = 15f;
// Screen 320 * 480 Medium dense
else if (w >= 71 && w <= 80) // Port MDPI
ts = 13f;
else if (w >= 81 && w <= 110) // Land LDPI W - 81 H - 58
ts = 15f;
else if (w >= 111 && w <= 220) // Landscape - Perfect
ts = 18f;
else if (w >= 221 && w <= 250)
ts = 20f;
setTileTextSize(ts);
}
ScreenInfo class contains setters/getters for following members :
public class ScreenInfo {
private int titleBarHeight, screenHeight, screenWidth;
private int rowHeight;
private LinearLayout.LayoutParams child1LayoutParams, child2LayoutParams;
private int _6tiles_Width; // Width of a Tile where 3 tiles on 2rows r shown
NOW comes actual implementation in Activity :
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.datapage);
root = (LinearLayout) findViewById(R.id.dataroot);
row1 = (LinearLayout) findViewById(R.layout.datarow1);
row2 = (LinearLayout) findViewById(R.layout.datarow2);
btn1 = (Button) findViewById(R.id.relationBtn);
btn2 = (Button) findViewById(R.id.productBtn);
btn3 = (Button) findViewById(R.id.bankBtn);
btn4 = (Button) findViewById(R.id.locationBtn);
btn5 = (Button) findViewById(R.id.curencyBtn);
btn6 = (Button) findViewById(R.id.dataReturnBtn);
root.post(new Runnable() {
public void run() {
Utility.findTitleBarHeight(getWindow());
// CALCULATE THE SIZE OF INNER LAYOUTS
//calculateChildSize();
LinearLayout.LayoutParams row1Params = (android.widget.LinearLayout.LayoutParams) row1.getLayoutParams();
LinearLayout.LayoutParams row2Params = (android.widget.LinearLayout.LayoutParams) row2.getLayoutParams();
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
Utility.calculateChildSize(root, row1Params, row2Params, metrics);
row1.setLayoutParams(Utility.scrnInfo.getChild1LayoutParams());
row2.setLayoutParams(Utility.scrnInfo.getChild2LayoutParams());
RefreshComponents();
}
});
}
protected void RefreshComponents() {
// Set background of the root
root.setBackgroundColor(Utility.getBackgroundColor());
// set Gradient Colors & text color of all buttons
RefreshGradientButtons();
}
protected void RefreshGradientButtons() {
GradientDrawable btnGradient = Utility.getButtonDrawable();
int i = -1;
for(i=0; i < row1.getChildCount(); i++) {
Button btn = (Button)row1.getChildAt(i);
btn.setBackgroundDrawable(btnGradient);
btn.setTextColor(Utility.getTextColor());
btn.setTextSize(Utility.getTileTextSize());
}
for(i=0; i < row2.getChildCount(); i++) {
Button btn = (Button)row2.getChildAt(i);
btn.setBackgroundDrawable(btnGradient);
btn.setTextColor(Utility.getTextColor());
btn.setTextSize(Utility.getTileTextSize());
}
}
Whenever screen is changed from Portrait to Landscape or vice-versa OR if at all density is changed at runtime, onCeate is called every such time. Hence this code is added in onCreate(), so the calculations and settings can be appropriately on spot.
In my app, this works like a charm in versions from 1.5 to 3.2 and all density's.
You will have to make changes for your requirement accordingly. As your design is just 3 buttons in a row, while my design for the above code is like Tiles on screen. 2 rows n 3 buttons in each row. I have kept the logs I had added as it will help you to debug and figure out your solution.
This will work 100%.
*I would still recommend to give a try to : just create a new xml and in LinearLayout as parent, add your LinearLayout of buttons and see. Does that work ? While executing try it in both the modes. In your LinearLayout try removing weightSum. According to me, this requirement should be achieved in xml itself. *
BEST LUCK.

HorizontalScrollView with arrows

I'm trying to make a scrollable horizontal menu using HorizontalScrollView using the layout shown below. The menu is scrollable using the previous/next arrow buttons or on fling. When the HorizontalScrollView reach one end I'd like the arrow at the same end to be hidden (in the image shown below I'd like the left arrow to be hidden).
How can I detect that the HorizontalScrollView has reached an end?
Thanks
<RelativeLayout android:background="#drawable/bg_home_menu"
android:layout_width="fill_parent" android:layout_height="45dp">
<ImageView android:id="#+id/previous" android:src="#drawable/arrow_l"
android:layout_height="14dp" android:layout_width="10dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true" />
<ImageView android:id="#+id/next" android:src="#drawable/arrow_r"
android:layout_height="14dp" android:layout_width="10dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true" />
<HorizontalScrollView android:id="#+id/horizontalScroll"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:scrollbars="none" android:fadingEdgeLength="30dp" android:layout_toLeftOf="#id/next"
android:layout_toRightOf="#id/previous" >
<LinearLayout android:id="#+id/home_menu"
android:orientation="horizontal" android:layout_width="wrap_content"
android:layout_height="fill_parent" android:gravity="center_vertical">
<Button android:id="#+id/btn_home" android:background="#drawable/btn_home_menu_on"
android:layout_height="35dp" android:layout_width="wrap_content" android:focusable="true"
android_clickable="false" android:text="#string/menu_home" android:textColor="#FFFFFF" android:tag="-1"/>
<!-- More are added dynamically -->
</LinearLayout>
</HorizontalScrollView>
</RelativeLayout>
There is no scroll listener for the HorizontalScrollView. What you can do is add an OnTouchListener to it This will fire continously when the user scrolls, and each time you can use the method getScrollX which returns the int.
Now 0 mean its left most, to find the right most(max scroll amount), you need to find the width of the child view of the horzontal scroll view. That is found by using the addOnGlobalLayoutListener else the width will always be 0 inside the onCreate method
Put this code in the onCreate method
final HorizontalScrollView hs = (HorizontalScrollView)findViewById(R.id.scroll);
ViewTreeObserver vto = hs.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
hs.getViewTreeObserver().removeGlobalOnLayoutListener(this);
maxScrollX = hs.getChildAt(0)
.getMeasuredWidth()-getWindowManager().getDefaultDisplay().getWidth();
}
});
hs.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.e("ScrollValue", Integer.toString(hs.getScrollX()));
if(hs.getScrollX() == maxScrollX){
Log.e("MaxRight", "MaxRight");
}
return false;
}
});
Use getScrollX() of the LinearLayout inside your scroller to determine which is the leftmost corner on screen. If it's 0, then left arrow should be disabled.
For the right arrow, retrieve the drawing rectangle's width, add getScrollX() and compare that to getMeasuredWidth (), if it's the same, you're at the right, no need for the right arrow.
So your code will look like this:
if (homeMenu.getScrollX()==0) {
hideLeftArrow();
} else {
showLeftArrow();
}
if (homeMenu.getDrawingRect().right == homeMenu.getMeasuredWidth()) {
hideRightArrow();
} else {
showRightArrow();
}
Of course you will have to put this in an event listener. I can only think of using your own HorizontalScrollView class, with the onScroll() method overwritten to perform the checks above, see this post.

scroll an image bigger than the screen and stop at its border on Android

I know how to display an image that is bigger than the screen. That's fairly simple and explained in details here, however, this method makes you able to scroll as far as you want, event if you have left the image and you just have black screen. I would like to know how we can make the scrolling stop when we reach the side of the picture...
Load your image into a WebView. Then you will get all the scroll behaviors you are looking for, and even the default zoom controls if you choose to turn them on...practically for free. Your only other option (to my knowledge) would be to used the 2D graphics APIs (Canvas, etc.) and create your own version of drawing tiles (like viewing a section of a map).
If your image is local, take a look at this example of reading local image data in from the SD Card. The cleaner approach to serving a local image in this case would be to create a ContentProvider and access the resource through a content:// URL in your WebView.
Example using the bundled image car.jpg in the assets directory of your project:
res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<WebView
android:id="#+id/web"
android:layout_width="150dip"
android:layout_height="150dip"
/>
</LinearLayout>
src/ImageViewer.java
public class ImageViewer extends Activity {
WebView webView;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
webView = (WebView)findViewById(R.id.web);
webView.loadUrl("file:///android_asset/car.jpg");
}
}
For an image bundled with your project, that's the simplest method. This does not work with images in your resources directory (like res/drawable). That path is not worth the code required to complete it.
In your Activity.onCreate():
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(...);
I was not sure which layout you exactly mean so I am posting 2 versions:
Version 1 (Buton below the image):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:orientation="vertical">
<ScrollView android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_weight="1"
android:fadingEdge="none" android:scrollbars="none">
<ImageView android:id="#+id/image" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:scaleType="center" />
</ScrollView>
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content" android:text="OK"
android:layout_gravity="center" />
</LinearLayout>
Version 2 (Button over the image - in z axis):
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent">
<ScrollView android:layout_width="fill_parent"
android:layout_height="fill_parent" android:fadingEdge="none"
android:scrollbars="none">
<ImageView android:id="#+id/image" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:scaleType="center" />
</ScrollView>
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content" android:text="OK"
android:layout_gravity="bottom|center_horizontal" />
</FrameLayout>
You can also try putting ScrollView inside a HorizontalScrollView.
Well I had same issue here is my solution:
Display display = getWindowManager().getDefaultDisplay();
screenSize = new Point();
display.getSize(screenSize);
Get screen size it will be required to set bottom and right boundaries
image.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
float curX, curY;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mx = event.getX();
my = event.getY();
rect = image.getDrawable().getBounds();
break;
case MotionEvent.ACTION_MOVE:
curX = event.getX();
curY = event.getY();
image.scrollBy(getX((int) (mx - curX)), getY((int) (my - curY)));
mx = curX;
my = curY;
break;
}
return true;
}
});
and finally two methods to set new scroll coordinates
private int getX(int x){
if (image.getScrollX() + x < 0 ){ //left side
return 0;
} else if (image.getScrollX() + x >= (rect.right - screenSize.x)){ //right side
return 0;
} else {
return x;
}
}
private int getY(int y){
if (image.getScrollY() + y < 0 ){ //top side
return 0;
} else if (image.getScrollY() + y >= (rect.bottom - screenSize.y)){ //bottom side
return 0;
} else {
return y;
}
}
Works great API 16+, hope it will help

Categories

Resources