I'm using a TouchImageView in my app in which I have an image which is larger than the screensize. When I start the activity that contains my TouchImageView it currently automatically shows the center of my image in the middle of the screen. I have to manually (using a drag gesture) make the top left-corner visibe. However, I would like to have the top-left corner of the image visible in the top left corner of my screen by default.
I tried imgView.setScrollPosition(0,0), but without any result.
I also tried setting the scaletype to "matrix", but this zooms out on the image, while I want the image to be shown in it's original size. Scaletypes fitStart and fitEnd are not supported by TouchImageView.
How can I scroll to the top left corner of my TouchImageView?
Here's my 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">
<com.frankd.wttv.TouchImageView
android:id="#+id/imageView"
android:layout_width = "wrap_content"
android:layout_height ="wrap_content"
android:scaleType="matrix"/>
</LinearLayout>
And here is how I open the layout and set the image.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.myLayout);
//set timetable image
TouchImageView imgView = (TouchImageView)findViewById(R.id.imageView);
imgView.setImageResource(R.drawable.myImage);
//TODO: scroll to top left corner of image
}
The cause of the problem is that scrollToPosition(x,y) in TouchImageView doens't use the x and y pixels as input, but instead a number between 0 and 1 that reflects a proportion of the image size.
Also the scrollToPosition(x,y) sets a point of the image in the center of the TouchImageView. So if you call scrollToPosition(0.5,0.5) on the TouchImageView, the center of the image is being displayed at the center of the TouchImageView. We need to calculate which point of the image needs to be placed in the center of the TouchImageView to get it aligned nicely.
I created the function scrollToTopLeft() in TouchImageView.java, which only works if you call it at the end of onMeasure() from within the TouchImageView.java file. If you call it earlier the getWidth() and getHeight() will return 0 as the view hasn't been sized yet.
public void scrollToTopLeft() {
try {
float x, y, viewWidth, viewHeight, viewCenterX, viewCenterY, imageWidth, imageHeight;
//these calls will only work if called after (or at the end of) onMeasure()
viewWidth = this.getWidth();
viewHeight = this.getHeight();
// get center of view
viewCenterX = viewWidth / 2;
viewCenterY = viewHeight / 2;
// get image height and width
imageWidth = getImageWidth();
imageHeight = getImageHeight();
//calculate the x and y pixels that need to be displayed in at the center of the view
x = viewWidth / imageWidth * viewCenterX;
y = viewHeight / imageHeight * viewCenterY;
//calculate the value of the x and y pixels relative to the image
x = x / imageWidth;
y = y / imageHeight;
setScrollPosition(x, y);
} catch (Exception E) {
Log.v(TAG, E.toString());
}
}
Related
I'm trying to vertically center a rotated and scaled View. It doesn't seem to matter if it is rotated or not (if I keep the scale at 1.0 and rotate the view, and change the x position of the view by using setX it works as expected).
I know the center of my container, and I also know the width of the rectangle that holds the View in the container.
I am setting X of the View to be: the middle of the container - view/2.
This works if I don't scale the view up or down, however if I scale the image up the image doesn't appear in the center, it is always off a noticeable amount.
// Get center of container
val rect = Rect()
containerView.getHitRect(rect)
val width = rect.right - rect.left
val centerContainerView = rect.left + width/2
// At this point assume myView is rotated and scaled up (using any one of the many translate, scale, rotate on touch libraries)
val viewRect = Rect()
myView.getHitRect(viewRect)
val viewWidth = viewRect.right - viewRect.left
val newX = centerContainerView - viewWidth/2
// Tap a button and run the below to center myView
myView.x = newX.toFloat()
SetX
I have game field which is a Group with Actors. The Group locketed in Table wich is locketed in ScrollPane. I have two Buttons to zoom in and zoom out the game field. Here is my code how I do it:
TextButton zoomInBtn = new TextButton("+", menuBtnStyle);
zoomInBtn.addListener(new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) {
float width = fieldGroup.getWidth();
float height = fieldGroup.getHeight();
float newWidth = width + width * 0.1f;
if (newWidth > myWorld.getMaxWidth()) {
newWidth = myWorld.getMaxWidth();
}
float newHeight = height * newWidth / width;
fieldGroup.setWidth(newWidth);
fieldGroup.setHeight(newHeight);
myWorld.setWidth(Math.round(newWidth));
fieldGroup.reinitialiseChildren();
Cell cell = fieldTable.getCell(fieldGroup);
cell.clearActor();
cell.setActor(fieldGroup);
}
});
TextButton zoomOutBtn = new TextButton("-", menuBtnStyle);
zoomOutBtn.addListener(new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) {
float width = fieldGroup.getWidth();
float height = fieldGroup.getHeight();
float newWidth = width - width * 0.1f;
if (newWidth < myWorld.getMinWidth()) {
newWidth = myWorld.getMinWidth();
}
float newHeight = height * newWidth / width;
Actor widget = scrollPane.getWidget();
fieldGroup.setWidth(newWidth);
fieldGroup.setHeight(newHeight);
myWorld.setWidth(Math.round(newWidth));
fieldGroup.reinitialiseChildren();
Cell cell = fieldTable.getCell(fieldGroup);
cell.clearActor();
cell.setActor(fieldGroup);
}
});
I change the size of my fieldGroup with Image Actors in it. And then readding it to Table.
The problem is: when I zoom with buttons it always zoom around left corner. I want it to zoom from canter of ScrollPane. I know that I can do it with Ortographic Camera, but it would be difficult, I think, to make it movements so smooth as ScrollPane. So maybe there is some way to do it with ScrollPane.
Every time you zoom in or out you would have to change the x and y position of the group relative to the zoom. You can do this using the setScrollx (and y) of your scroll pane.
You need to set so that the middle of the part you are viewing stays in the middle of the scrollpane. You can work out middle of newWidth by dividing it by 2. If the scrollPane is fullScreen you can half the value obtained by Gdx.graphics.getwidth();. The difference between these two is then the value which will keep the middles aligned.
newXvalue =(newWidth/2) - ((Gdx.graphics.getWidth())/2);
scrollPane.setScrollx(newXvalue);
The same should be done for y.
Note: if you want to zoom and move at same time, this will not work, I would recommend using orthographic camera with a gesture listener for that.
Given a simple RelativeLayout like this:
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#0fffff">
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:src="#drawable/img001" />
</RelativeLayout>
the left/top spacing between the layout border and the image border depends on the W/H ratio of the image being load in the imageView.
How can I know (programmatically) the real margin (width and height of the cyan area) after an image is shown in this layout?
This method will calculate the new rectangle which bounds the object after FIT_CENTER and all other related values.
It should work on all cases of object and container.
public static Rect calculateFitCenterObjectRect(float containerWidth, float containerHeight, float objectWidth, float objectHeight) {
// scale value to make fit center
double scale = Math.min( (double)containerWidth / (double)objectWidth, (double)containerHeight / (double)objectHeight);
int h = (int) (scale * objectHeight); // new height of the object
int w = (int) (scale * objectWidth); // new width of the object
int x = (int) ((containerWidth - w) * 0.5f); // new x location of the object relative to the container
int y = (int) ((containerHeight - h) * 0.5f); // new y location of the object relative to the container
return new Rect(x, y, x + w, y + h);
}
You can use FrameLayout to position the view wherever you want after using the previous method with the new x, y, width, height of the scaled object.
If you know the width of the ImageView, like this
int ivWidth = iv.getMeasuredWidth();
and the total width of the layout (your RelativeLayout), like this
int layoutWidth = yourLayout.getWidth();
then, you can easily get the horizontal margin, like this
int horizontalMargin = (layoutWidth - ivWidth)/2;
And the same goes for height.
You should call functions like getWidth and getHeight after the dimensions of your layout have been calculated, as described by Veer's and Khan's answer on How to get the width and height of an Image View in android?.
Calling getWidth or getHeight in onCreate will return 0.
I have an Android button on a RelativeLayout which I want to animate.
The animation is currently done with a ObjectAnimator to move the button 50dp up and down on a scroll event.
The position of the button is currently calculated programmatically with
height = context.getResources().getDisplayMetrics().heightPixels
y = height - buttonheight - bottomMargin
My problem with this is, that the calculation works fine in the portrait mode, but as soon as I switch to landscape mode the distance between bottom and button is bigger than in portrait mode.
What did I miss?
Try to convert pixels to dp right before putting your button on the layout:
public static float convertPxToDp(int px, Context context) {
final float scale = context.getResources().getDisplayMetrics().density;
float dp = (float) ((px - 0.5f) / scale);
return dp;
}
This should work!
This is correct and obvious when you will change your orientation your height calculation value will also change as display matrics.heightPixel will return more height in case of landscape mode.
height = context.getResources().getDisplayMetrics().heightPixels
It will return more value and accordingly it will be recalculated. If you want to just give fixed value of space between button and bottom than you have to recheck your height calculation idea.
first try to convert pixel to dp like this :
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;
then i think you must change your algorithm in landscape mode
Converting to dp did not work.
So my solution is to wrap a RelativeLayout around my button, and animate the button relative to its parent, which is fixed.
<RelativeLayout android:layout_width="56dp"
android:layout_height="85dp"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginRight="13dp">
<Button
android:id="#+id/button"
android:layout_marginTop="10dp"
android:layout_width="56dp"
android:layout_height="56dp"/>
</RelativeLayout>
I am trying to make a Custom ChedckBox and having a trouble centring the button part of it. Here is the code :
<FrameLayout
android:layout_width="#dimen/checkbox_height"
android:layout_height="#dimen/checkbox_height"
android:background="#drawable/checkbox_background_info"
android:padding="5dp" >
<CheckBox
android:id="#+id/classification_uk_selected"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:button="#drawable/checkbox_star_info">
</CheckBox>
</FrameLayout>
The Drawbale just has a yellow star with no background for enabled and grey one for disabled. It stays to the left handside and I cannot get it centered
Thanks for help
If you change FrameLayout to RelativeLayout you can just set android:center_in_parent to true;
in your frame layout set gravity as center.
android:gravity="center"
I dont believe this is possible (atleast not in API version 8)
Here is the code from CompoundButton.onDraw, which seems to indicate the CompoundButton draws buttonDrawable (which represents your checkbox image) within a bounding rect which has an offset of 0 in the parent view.
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
final Drawable buttonDrawable = mButtonDrawable;
if (buttonDrawable != null) {
final int verticalGravity = getGravity() & Gravity.VERTICAL_GRAVITY_MASK;
final int height = buttonDrawable.getIntrinsicHeight();
int y = 0;
switch (verticalGravity) {
case Gravity.BOTTOM:
y = getHeight() - height;
break;
case Gravity.CENTER_VERTICAL:
y = (getHeight() - height) / 2;
break;
}
buttonDrawable.setBounds(0, y, buttonDrawable.getIntrinsicWidth(), y + height);
buttonDrawable.draw(canvas);
}
}
Instead, try setting the width of the CheckBox to be slightly greater (in dp) than the size of the image you're using. This squeezes the button drawable and it doesn't render with all the white space on the right.