Android imageView gets out of screen boundries - android

I am using onTouchEvent to detect screen swipe and change ImageView position, my problem is the ImageView can get out of screen. here is my code:
To get RelativeLayout bounds
rlt = (RelativeLayout) findViewById(R.id.layout);
rlt.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
rlt.getViewTreeObserver().removeOnGlobalLayoutListener(this);
lwidth = rlt.getWidth();
lheight = rlt.getHeight();
Toast.makeText(MainActivity.this,"" + lwidth + lheight, Toast.LENGTH_SHORT).
show();
}
});
Or other way - to get Screen bounds -
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
lheight = displaymetrics.heightPixels;
lwidth = displaymetrics.widthPixels;
to set the position of the ImageView (example of right swipe)
if (x2 > x1) { // To the right (x1=swipe ends finger position, x2= swipe starts finger position)
imageView.setX(imageView.getX() + 50);
if(imageView.getX()>1440)
imageView.setX(1440-imageView.getWidth());
Toast.makeText(this, "right" + imageView.getX(), Toast.LENGTH_SHORT).
show();
}
I am testing this on Galaxy S6, width should be 1440 pixels, I checked and the ImageView(40px40p) can get to 1333p max and there you see only half of it. I want it to stop at 1283p in this case but also support other phones, universally code. Thank you.
Note - when the ImageView is imageView.setX(1330) I can't see it at all but my device is 1440 width.

Just get width/height of viewgroup where your view placed and work with them.

Related

Ho to get s8 useable screen android?

I am noob in android. My problem about useable height of 18:9 devices.
When I try to get useable screen in these aspect-ratio my application is woking fine all android devices but when ı compile in Samsung Galaxy s8 it is not working.
I am trying to get useable screen of devices.
I have already tried method which in these links
https://stackoverflow.com/questions/43628047/how-to-support-189-aspect-ratio-in-android-apps
https://android-developers.googleblog.com/2017/03/update-your-app-to-take-advantage-of.html
And I use dynamically
DisplayMetrics metrics = this.getResources().getDisplayMetrics();
width = metrics.widthPixels;
height = metrics.heightPixels ;
And I tried
private int getSoftButtonsBarHeight() {
// getRealMetrics is only available with API 17 and +
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int usableHeight = metrics.heightPixels;
getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
int realHeight = metrics.heightPixels;
if (realHeight > usableHeight)
return realHeight - usableHeight;
else
return 0;
}
return 0;
}
And when I try to set params MATCH_PARENT height it is working good. But I need to find useable height pixel to desing my other views proportionally .
Actually these code DisplayMetrics metrics = this.getResources().getDisplayMetrics();
height = metrics.heightPixels ; working in my Activity but when I try to use it in another window which I extend from FramaLayout and add to activity it is not working.
Here is my code block
public class StudentLoginActivity extends Activity { ...
FrameLayout.LayoutParams containerParams = new ScrollView.LayoutParams(width, height-sb);
container = new FrameLayout(this);
container.setLayoutParams(containerParams);
container.setBackgroundColor(Color.rgb(248,248,248));
loginStudentView = new StudentLoginView(this);
container.addView(loginStudentView); ...
}
public class StudentLoginView extends FrameLayout { ...
FrameLayout.LayoutParams cp = new FrameLayout.LayoutParams(width, height);
setLayoutParams(cp); ...
}
But this problem related with android navigationBar height because when I show navigation bar there is no problem but if I hide navigationBar it is not resize application still working that there is a navigation bar on screen (but I hide the navigationBar).
My problem is very similar this link
android Navigation Bar hiding and persantage of usable screen overlap
You can get the useable height (even on Galaxy S8 with or without shown NavBar) with the decorview:
//Get the correct screen size even if the device has a hideable navigation bar (e.g. the Samsung Galaxy S8)
View decorView = getWindow().getDecorView(); //if you use this in a fragment, use getActivity before getWindow()
Rect r = new Rect();
decorView.getWindowVisibleDisplayFrame(r);
int screenHeight = r.bottom; // =2220 on S8 with hidden NavBar and =2076 with enabled NavBar
int screenWidth = r.right; // =1080 on S8
If you have a view that is set to match the parent width and height (the whole screen), you can attach a listener to that view and then get its width and height.
View myView = findViewById(R.id.my_view);
myView.addOnLayoutChangeListener(new OnLayoutChangeListener() {
#Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight,
int oldBottom) {
// its possible that the layout is not complete in which case
// we will get all zero values for the positions, so ignore the event
if (left == 0 && top == 0 && right == 0 && bottom == 0) {
return;
}
// Do what you need to do with the height/width since they are now set
}
});
This answer was taken from here.

How to scale imageview image to specific size?

I created an imageview image, but I want to scale it to be no greater than a fifth of the width and a sixth of the height of the android device's screen size.
Here I get the width and height of the screen:
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int width = metrics.widthPixels;
int height = metrics.heightPixels;
here I create my imageview:
ImageView imageView = new ImageView(this);
imageView.setImageResource(icons[0]);
and here I try to scale my imageview:
imageView.getDrawable().setBounds(0, 0, width/5, height/6);
This last part is the stickler. After typing this in I get no errors and my program runs normally - but the image is not scaled. Basically that last line of code seems to have no effect and I have no idea why, any pointers?
Rest of my code:
imageView.setAdjustViewBounds(true);
int mh = imageView.getDrawable().getIntrinsicHeight();
int mw = imageView.getDrawable().getIntrinsicWidth();
imageView.setX(width/2 - Math.round(width/5));
imageView.setY(height/2 - Math.round(height/6) - mActionBarSize);
relativeLayout.addView(imageView);
setContentView(relativeLayout);
do this :
imageView.getLayoutParams().height = (int) Math.round(height/6);
imageView.getLayoutParams().width = (int) Math.round(width/5);
imageView.requestLayout(); // If you're setting the height/width after the layout has already been 'laid out'
see this link to learn more about requestLayout():
Call this when something has changed which has invalidated the layout of this view. This will schedule a layout pass of the view tree.
But ususally the view is calling it automatically, you don't have to care about that... (So for me I use it to force the view to do what I want to do)
Use this
ImageView imgView = (ImageView) findViewById(R.id.pageImage);
imgView.getLayoutParams().height = 100;
imgView.getLayoutParams().width = 100;

Best solution to draw responsive areas on image

I'm wondering what would be the best solution to get to the result shown below.
Here is what i've found so far:
an ImageView for the forest and a transparent surfaceView (to handle touch) on which I would draw the rectangles?
Or...
Just One SurfaceView with the image set as background and rectangles directly drawn on...?
For those 2 I've already chosen a RelativeLayout.
Which of those 2 would be the most efficient and easiest to do?
Or maybe there is another way which I haven't think about.
In any case thanks for your advice, here is what I tend to...
I've implemented this by placing the image in a RelativeLayout (FrameLayout would work too), and then adding each outlined view programatically. If you know the x and y origin (perhaps as a ratio to the image) and the size for each area, you can easily inflate each view/area (with a black border, transparent center), make it clickable and set a listener, and then set it's origin by adjusting it's margins. You may want to perform all of this after the image has finished laying out:
I put this in onActivityCreated of my Fragment, but other lifecycle methods would work too...
ViewTreeObserver vto = image.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (image.getMeasuredHeight() > 0) {
addHotSpots();
ViewTreeObserver obs = image.getViewTreeObserver();
obs.removeGlobalOnLayoutListener(this);
}
}
});
And this is how I actually place all the hotspots/areas:
protected void addHotSpots() {
HotSpot[] hotSpots = res.hotspots;
for (HotSpot hs : hotSpots) {
addHotSpotToImage(hs);
}
private void addHotSpotToImage(HotSpot hs) {
int height = image.getMeasuredHeight();
int width = image.getMeasuredWidth();
//this piece will probably be different for you
//depending on what you know about the area's intended size/position
double hsHeightRatio = hs.lr.y - hs.ul.y;
double hsWidthRatio = hs.lr.x - hs.ul.x;
double leftMargin = hs.ul.x * width;
double topMargin = hs.ul.y * height;
double hsHeight = height * hsHeightRatio;
double hsWidth = width * hsWidthRatio;
LayoutInflater vi = (LayoutInflater) image.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View newSpot = vi.inflate(R.layout.question_hotspot, null);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams((int) hsWidth, (int) hsHeight);
newSpot.setTag(hs.key);
newSpot.setFocusable(true);
newSpot.setClickable(true);
newSpot.setFocusableInTouchMode(true);
newSpot.setOnTouchListener(this);
params.topMargin = (int) topMargin;
params.leftMargin = (int) leftMargin;
image.addView(newSpot, params);
}

Android how to programmatically create scrollview and add programmatically created views into it

Alright I'm trying to build an activity that has a horizontal scrollview, that the user can swipe through, to view different "pages". My train of thought is these "pages" will be views. The following is a mockup of my idea (to mess around to see if it works)
I've experimented with this as follows:
My content view is set to the the scrollview. (unsure if this is an incorrect approach)
I create the scrollview, and place a view into it as follows:
private void setupScrollView()
{
Display display = getWindowManager().getDefaultDisplay();
DisplayMetrics outMetrics = new DisplayMetrics ();
display.getMetrics(outMetrics);
float density = getResources().getDisplayMetrics().density;
float dpHeight = outMetrics.heightPixels / density;
float dpWidth = outMetrics.widthPixels / density;
int width = (int)MeasureUtils.convertDpToPixel(dpWidth, getApplicationContext());
int height = (int)MeasureUtils.convertDpToPixel(dpHeight, getApplicationContext());
_scrollView = new HorizontalScrollView(getApplicationContext());
_scrollView.setBackgroundColor(Color.CYAN);
_scrollView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
Log.i("DEBUG", "Screen dp width = " + dpWidth + " screen dp height = " + dpHeight);
TextView view = new TextView(getApplicationContext());
view.setBackgroundColor(Color.RED);
view.setText("TEST");
view.setX(0); // Start at the left of the scrollview.
view.setWidth(width); // Size it so that it fills to the right of the scrollview.
TextView view2 = new TextView(getApplicationContext());
view2.setBackgroundColor(Color.GREEN);
view2.setText("TEST2");
view2.setX(width); // Start the second "page/view" offscreen to the right where i can scroll to it
view.setWidth(width); // Fill the screen width
LinearLayout layout = new LinearLayout(getApplicationContext());
layout.setBackgroundColor(Color.MAGENTA);
layout.addView(view);
layout.addView(view2);
_scrollView.addView(layout);
}
The idea above is that I will see a view, that takes up the screen, representing a page. This view should be "RED" in color. I can then scroll horizontally to the right and see the second view (view2) representing the next page. This view should be "GREEN" in color. This does not happen. I end up seeing what looks like 1/3rd or 1/2 of my screen being view1, the linearlayout taking up almost the whole screen (a bit of a gap to the right edge where the CYAN from the scrollview bleeds through).
Am I approaching this the wrong way, and/or is it possible to make this work the way I'm going at it?
You probably do not want to use a horizontalscroll view to create "pages".
Try looking at PageViewer
This automatically builds in all the sywpe and inflating logic for you.
Basically you will get a call to inflate a certain page. There you can then create your view (dynamically if you wish) and then just return the root to be rendered.
Alright I've figured out what I was doing wrong, and it turned out to be something very small...
The complete code is here:
private void setupScrollView()
{
Display display = getWindowManager().getDefaultDisplay();
DisplayMetrics outMetrics = new DisplayMetrics ();
display.getMetrics(outMetrics);
float density = getResources().getDisplayMetrics().density;
float dpHeight = outMetrics.heightPixels / density;
float dpWidth = outMetrics.widthPixels / density;
int width = (int)MeasureUtils.convertDpToPixel(dpWidth, getApplicationContext());
int height = (int)MeasureUtils.convertDpToPixel(dpHeight, getApplicationContext());
_scrollView = new HorizontalScrollView(getApplicationContext());
_scrollView.setBackgroundColor(Color.CYAN);
_scrollView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
Log.i("DEBUG", "Screen dp width = " + dpWidth + " screen dp height = " + dpHeight);
TextView view = new TextView(getApplicationContext());
view.setBackgroundColor(Color.RED);
view.setText("TEST");
view.setX(0);
view.setWidth(width);
view.setHeight(height - 50);
TextView view2 = new TextView(getApplicationContext());
view2.setBackgroundColor(Color.GREEN);
view2.setText("TEST2");
view2.setX(0);
view2.setWidth(width);
view2.setHeight(height - 50);
LinearLayout layout = new LinearLayout(getApplicationContext());
layout.setBackgroundColor(Color.MAGENTA);
layout.addView(view);
layout.addView(view2);
_scrollView.addView(layout);
}
This creates a horizontal scrollview programmatically, as I had, but the problem was that I was setting the second view to be "width" away, when it should be set to "0"as can be seen by:
view2.setX(0);
With that, I get 2 "views" that resemble pages in my scrollview that I can swipe through. Each taking up the whole page.
Hate having the code close and it being a simple fix that I missed :|
Hope this helps anyone else that tries to do it this way. I'm going to look into the PageViewer as Frank suggested.

Android: Get Screen size for the root Layout only

Please get me correctly over here :
I want to get the height/width of the space available to the Activity/Layout in onCreate() method to calculate the height that can be given to child layouts. I can get the screen size using :
root = (LinearLayout) findViewById(R.id.mainroot); // Main layout of LinearLayout
android.view.Display display = getWindowManager().getDefaultDisplay();
int height = Display.getHeight(); // I know this is deprecated have hence used
int width = Display.getWidth(); // DisplayMetrics
int childWidth, childHeight;
DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics(metrics);
//int density = metrics.densityDpi;
height = metrics.heightPixels; //480
width = metrics.widthPixels; //320
This both the methods/ways gives me same height and width i.e. size of full screen. What I am looking for is to get actual height that is avaialbe for the layout after deduction of Application Title, Status Bar, etc.
Any idea how to get this. OR to get the sizes of titles, etc - what all should be counted over here. On emulator I see 2 bars on top - 1 must be application titile what an be the other one. I can get heights of them all and deduct from screen height.
ONE more point : In this case I will be setting the height programamtically so it will be pixel based (as I can setheight in pixels only I guess) will that affect in density factor with differnet screen sizes. What can be a way to calculate height (lets say 50%) for child layout that will be same for any density o so.
SOLUTION :
In my onCreate(), I added the following lines :
setContentView(R.layout.mainpage);
root = (LinearLayout) findViewById(R.id.mainroot);
root.post(new Runnable() {
public void run() {
Rect rect = new Rect();
Window win = getWindow();
win.getDecorView().getWindowVisibleDisplayFrame(rect);
int statusHeight = rect.top;
int contentViewTop = win.findViewById(Window.ID_ANDROID_CONTENT).getTop();
titleHeight = contentViewTop - statusHeight;
Log.i(Utility.TAG, "titleHeight = " + titleHeight + " statusHeight = " + statusHeight + " contentViewTop = " + contentViewTop);
// CALCULATE THE SIZE OF INNER LAYOUTS
calculateChildSize();
}
});
With the above code, I get the values of titleBar & statusBar. On deducting it from metrics.heightPixels; I get the required height of the screen.
Good Point is this code works for all density's.
Hope this helps others too.
FOR IMPROVEMENT : I have to do similar calculations for all Activities in my application, so was thinking about writing this code only once. I can save teh titleHeight to a static variable so can use in all activities.
BUT
Can the user change the phone's density at runtime.
If so, then the Activity's onCreate will be called again or not ?
If not, then can I trap the density change event where I can add this code and make the current activity to refresh.
Any idea suggestions for improving is appreciated.
//Where rootView is the object for the root view of your application
final int viewWidt = rootView.getMeasuredWidth();
There is very easy method for that. doOnLayout() method is called as soon as layout is measured and ready:
rootView.doOnLayout {
rootView.getMeasuredWidth()
rootView.getMeasuredHeight()
}

Categories

Resources