I am making an app in which a RelativeLayout fits completely in the screen. I have than added a button which zooms in this layout using setScaleX() an setScaleY() to the layout. As a consequence (obviously) the whole layout does'nt fit in the screen anymore. So I first thought using a ScrollView to be able to move in the RelativeLayout, but this didn't work. Any suggestions? Thanks in advance.
Here is the xml code:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/layoutMain"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="phou.minesweeper.GameActivity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#+id/chronometer"
android:layout_below="#+id/textViewBest">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_centerInParent="true"
android:layout_centerVertical="true">
<RelativeLayout
android:id="#+id/grid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerInParent="true"
android:layout_centerVertical="true"></RelativeLayout>
</ScrollView>
</RelativeLayout>
</RelativeLayout>
The RelativeLayout which i'm zooming is the one with id = grid.
The xml code is so short because all of the views are created in java.
As you are manipulating the view size in Java using setScaleX/Y, you probably need to implement an onTouchListener on the RelativeLayout to handle drag motion events to allow you to move the entire layout programatically.
Assuming the view you are scaling is #id/grid, a simple OnTouchListener would look something like this.
final View grid = findViewById(R.id.grid);
final Point dispSize = new Point();
getWindowManager().getDefaultDisplay().getSize(dispSize);
grid.setOnTouchListener(new OnTouchListener() {
private PointF mAnchor = new PointF();
private PointF mTouchPoint = new PointF();
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
mTouchPoint.set(motionEvent.getX(), motionEvent.getY());
switch (motionEvent.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
mAnchor.set(mTouchPoint);
return true;
case MotionEvent.ACTION_MOVE:
float dx = mTouchPoint.x - mAnchor.x;
float dy = mTouchPoint.y - mAnchor.y;
float left = grid.getX() + dx;
float right = left + grid.getWidth();
float top = grid.getY() + dy;
float bottom = top + grid.getHeight();
if (grid.getWidth() > dispSize.x) {
if (left > 0f) {
left = 0f;
}
if (right < dispSize.x) {
left += dispSize.x - right;
}
}
if (grid.getHeight() > dispSize.y) {
if (top > 0f) {
top = 0f;
}
if (bottom < dispSize.y) {
top += dispSize.y - bottom;
}
}
grid.setX(left);
grid.setY(top);
return true;
default:
return true;
}
}
});
Note that this OnTouchListener will only receive touch events that have NOT been intercepted by the content views of the RelativeLayout (which we don't see in the XML code). This means that the content views need to pass any unconsumed touch events up the hierarchy by returning false in their own touch/gesture listeners.
Related
I have bottom sheet, and I want to change its behavior so it would work like on the main screen of Google Maps application, where you can expand it to any position and leave it there and it won't automatically stick to the bottom or to the top. Here's my layout with bottom sheet:
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.gms.maps.MapView
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<View
android:id="#+id/shadow"
android:layout_width="match_parent"
android:layout_height="16dp"
android:background="#drawable/shape_gradient_top_shadow"
app:layout_anchor="#+id/map_bottom_sheet" />
<LinearLayout
android:id="#+id/map_bottom_sheet"
android:layout_width="match_parent"
android:layout_height="300dp"
android:fillViewport="false"
android:orientation="vertical"
app:behavior_peekHeight="50dp"
android:background="#color/lightGray"
app:layout_behavior="android.support.design.widget.BottomSheetBehavior">
<include layout="#layout/bottom_sheet_top_buttons"/>
<android.support.v4.widget.NestedScrollView
android:id="#+id/bottom_sheet_content_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/lightGray"/>
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
What I need in essence is eliminate forcing of STATE_EXPANDED and STATE_COLLAPSED states when dragging is ended.
Here's a visual explanation of what I try to achieve:
As you can see, bottom sheet doesn't automatically anchor to the top or the bottom but stays at whatever position it was left.
Copy the code from android.support.design.widget.BottomSheetBehavior to make your own custom behavior. Then modify the onViewReleased() method which is responsible for the movement of the sheet after the drag ends. You also have to introduce a new state besides the existing ones - the state is helpful to restore the position and let others know in which state your sheet is at the moment with getState().
#Override
public void onViewReleased(View releasedChild, float xVel, float yVel) {
int top;
#State int targetState;
// Use the position where the drag ended as new top
top = releasedChild.getTop();
// You have to manage the states here, too (introduce a new one)
targetState = STATE_ANCHORED;
if (mViewDragHelper.settleCapturedViewAt(releasedChild.getLeft(), top)) {
setStateInternal(STATE_SETTLING);
ViewCompat.postOnAnimation(releasedChild, new SettleRunnable(releasedChild, targetState));
} else {
setStateInternal(targetState);
}
}
I have created a proof of concept originating from the orginal source code from the design library. You can view it here. The problem with the original behavior is it doesn't allow flings, and most methods are private so extending the class and overriding some methods in an attempt to achieve it won't get you very far either. My implementation allows for optional snapping behavior, transient states (don't automatically snap after drag) and customizations around setting peek height and max height.
Hi Alex you can try this code for similar expected behaviour, it is not as optimised but it will help you to understand the concept.
final DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
bottomSheetBehavior.setPeekHeight(200);
// set callback for changes
bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
#Override
public void onStateChanged(#NonNull View bottomSheet, int newState) {
Log.d(TAG, "onStateChanged: " + bottomSheet.getY() + "::" + bottomSheet.getMeasuredHeight() + " :: " + bottomSheet.getTop());
}
#Override
public void onSlide(#NonNull View bottomSheet, float slideOffset) {
ViewGroup.LayoutParams params = bottomSheet.getLayoutParams();
params.height = Math.max(0, metrics.heightPixels - (int) bottomSheet.getTop());
bottomSheet.setLayoutParams(params);
}
});
it is almost 6 days traying to move the layout, but no success at all, trying alot of helps from internet but none helps..
I want llPic1 and llPic2 to be moved above ivNjeri with OnTouchListener.
So player to dicide which one need to be moved above ivNjeri.
With this code it vibrates on move and llPic1 and llPic2 goes under ivNjeri:
float dx = 0, dy = 0, x = 0, y = 0;
#Override
public boolean onTouch(View view, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
x = event.getX();
y = event.getY();
dx = x - view.getX();
dy = y - view.getY();
}
break;
case MotionEvent.ACTION_MOVE: {
view.setX(event.getX() - dx);
view.setY(event.getY() - dy);
}
break;
}
return true;
}
I'm also trying alot of other codes but none works, any help will be very very appriciated :)
You should use only 1 ViewGroup which holds all the images including an image to be overlapped and images to move.
Why image cannot go over the big image?
The small image on right side is inside of nested LinearLayout which is restricting the small image to be within the LinearLayout. That is why you can move the image inside of the child LinearLayout but not go beyond the boundary.
One example to fix it using RelativeLayout and fixed width on big image:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<ImageView
android:id="#+id/bigimage"
android:layout_width="200dp"
android:layout_height="300dp"
android:src="#drawable/ic_launcher"/>
<ImageView
android:id="#+id/smallimage"
android:layout_width="match_parent"
android:layout_height="100dp"
android:src="#drawable/ic_launcher"
android:layout_toRightOf="#id/bigimage"/>
<ImageView
android:layout_width="match_parent"
android:layout_height="100dp"
android:src="#drawable/ic_launcher"
android:layout_toRightOf="#id/bigimage"
android:layout_below="#id/smallimage"/>
</RelativeLayout>
If you want to keep the precise weight, check out
https://developer.android.com/reference/android/support/percent/PercentFrameLayout.html
https://developer.android.com/reference/android/support/percent/PercentRelativeLayout.html
This can give you weight control and can hold all views in 1 ViewGroup.
If you are trying only to animate view why you dont use Animation for it like this:
TranslateAnimation animation = new TranslateAnimation(0.0f, 400.0f,0.0f, 0.0f);
// new TranslateAnimation(xFrom,xTo, yFrom,yTo)
animation.setDuration(5000); // animation duration
animation.setRepeatCount(1); // animation repeat count
animation.setRepeatMode(1); // repeat animation (left to right, right to left )
//animation.setFillAfter(true);
llPic1.startAnimation(animation); // start animation
you can try this tutorial link. i think you need remove your pic 1 or pic2 (if you want disapeare after dragging.) and then you should add another image view on ivNjeri view
I want to know how to adjust my listview activity_main_menu_listview in center of LinearLayout. I tried with gravity but its not work for me but when I give it margin so it worked. But i want it auto, so how can i do it?
Thanks
<com.entropy.slidingmenu2.layout.MainLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<!-- This holds our menu -->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
<ListView
android:id="#+id/activity_main_menu_listview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#ffffff"
android:divider="#android:color/transparent"
android:cacheColorHint="#00000000" >
</ListView>
</LinearLayout>
<!-- This holds our content-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<!-- This acts as Actionbar -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ffffff"
android:layout_marginTop="5dp"
android:layout_marginLeft="5dp"
android:orientation="horizontal" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="toggleMenu"
android:background="#drawable/menu_btn"
android:id="#+id/activity_main_content_button_menu" />
</LinearLayout>
<!-- This is where fragment will show up -->
<FrameLayout
android:id="#+id/activity_main_content_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</FrameLayout>
</LinearLayout>
MainLayout Code:
public class MainLayout extends LinearLayout {
// Duration of sliding animation, in miliseconds
private static final int SLIDING_DURATION = 500;
// Query Scroller every 16 miliseconds
private static final int QUERY_INTERVAL = 16;
// MainLayout width
int mainLayoutWidth;
// Sliding menu
private View menu;
// Main content
private View content;
// menu does not occupy some right space
// This should be updated correctly later in onMeasure
private static int menuRightMargin = 120;
// The state of menu
private enum MenuState {
HIDING,
HIDDEN,
SHOWING,
SHOWN,
};
// content will be layouted based on this X offset
// Normally, contentXOffset = menu.getLayoutParams().width = this.getWidth - menuRightMargin
private int contentXOffset;
// menu is hidden initially
private MenuState currentMenuState = MenuState.HIDDEN;
// Scroller is used to facilitate animation
private Scroller menuScroller = new Scroller(this.getContext(),
new EaseInInterpolator());
// Used to query Scroller about scrolling position
// Note: The 3rd paramter to startScroll is the distance
private Runnable menuRunnable = new MenuRunnable();
private Handler menuHandler = new Handler();
// Previous touch position
int prevX = 0;
// Is user dragging the content
boolean isDragging = false;
// Used to facilitate ACTION_UP
int lastDiffX = 0;
// Constructor
// 3 parameters constructor seems to be unavailable in 2.3
/*
public MainLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
*/
public MainLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MainLayout(Context context) {
super(context);
}
// Overriding LinearLayout core methods
// Ask all children to measure themselves and compute the measurement of this
// layout based on the children
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mainLayoutWidth = MeasureSpec.getSize(widthMeasureSpec);
menuRightMargin = mainLayoutWidth * 30 / 100;
// Nothing to do, since we only care about how to layout
}
// This is called when MainLayout is attached to window
// At this point it has a Surface and will start drawing.
// Note that this function is guaranteed to be called before onDraw
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
// Get our 2 child View
menu = this.getChildAt(0);
content = this.getChildAt(1);
// Attach View.OnTouchListener
content.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return MainLayout.this.onContentTouch(v, event);
}
});
// Initially hide the menu
menu.setVisibility(View.GONE);
}
// Called from layout when this view should assign a size and position to each of its children
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
//Log.d("MainLayout.java onLayout()", "left " + left + " top " + top + " right " + right + " bottom " + bottom);
//Log.d("MainLayout.java onLayout()", "getHeight " + this.getHeight() + " getWidth " + this.getWidth());
// True if MainLayout 's size and position has changed
// If true, calculate child views size
if(changed) {
// Note: LayoutParams are used by views to tell their parents how they want to be laid out
//Log.d("MainLayout.java onLayout()", "changed " + changed);
// content View occupies the full height and width
LayoutParams contentLayoutParams = (LayoutParams)content.getLayoutParams();
contentLayoutParams.height = this.getHeight();
contentLayoutParams.width = this.getWidth();
// menu View occupies the full height, but certain width
LayoutParams menuLayoutParams = (LayoutParams)menu.getLayoutParams();
menuLayoutParams.height = this.getHeight();
menuLayoutParams.width = this.getWidth() - menuRightMargin;
}
// Layout the child views
menu.layout(left, top, right - menuRightMargin, bottom);
content.layout(left + contentXOffset, top, right + contentXOffset, bottom);
}
// Custom methods for MainLayout
// Used to show/hide menu accordingly
public void toggleMenu() {
// Do nothing if sliding is in progress
if(currentMenuState == MenuState.HIDING || currentMenuState == MenuState.SHOWING)
return;
switch(currentMenuState) {
case HIDDEN:
currentMenuState = MenuState.SHOWING;
menu.setVisibility(View.VISIBLE);
menuScroller.startScroll(0, 0, menu.getLayoutParams().width,
0, SLIDING_DURATION);
break;
case SHOWN:
currentMenuState = MenuState.HIDING;
menuScroller.startScroll(contentXOffset, 0, -contentXOffset,
0, SLIDING_DURATION);
break;
default:
break;
}
// Begin querying
menuHandler.postDelayed(menuRunnable, QUERY_INTERVAL);
// Invalite this whole MainLayout, causing onLayout() to be called
this.invalidate();
}
// Query Scroller
protected class MenuRunnable implements Runnable {
#Override
public void run() {
boolean isScrolling = menuScroller.computeScrollOffset();
adjustContentPosition(isScrolling);
}
}
// Adjust content View position to match sliding animation
private void adjustContentPosition(boolean isScrolling) {
int scrollerXOffset = menuScroller.getCurrX();
//Log.d("MainLayout.java adjustContentPosition()", "scrollerOffset " + scrollerOffset);
// Translate content View accordingly
content.offsetLeftAndRight(scrollerXOffset - contentXOffset);
contentXOffset = scrollerXOffset;
// Invalite this whole MainLayout, causing onLayout() to be called
this.invalidate();
// Check if animation is in progress
if (isScrolling)
menuHandler.postDelayed(menuRunnable, QUERY_INTERVAL);
else
this.onMenuSlidingComplete();
}
// Called when sliding is complete
private void onMenuSlidingComplete() {
switch (currentMenuState) {
case SHOWING:
currentMenuState = MenuState.SHOWN;
break;
case HIDING:
currentMenuState = MenuState.HIDDEN;
menu.setVisibility(View.GONE);
break;
default:
return;
}
}
// Make scrolling more natural. Move more quickly at the end
// See the formula here http://cyrilmottier.com/2012/05/22/the-making-of-prixing-fly-in-app-menu-part-1/
protected class EaseInInterpolator implements Interpolator {
#Override
public float getInterpolation(float t) {
return (float)Math.pow(t-1, 5) + 1;
}
}
// Is menu completely shown
public boolean isMenuShown() {
return currentMenuState == MenuState.SHOWN;
}
// Handle touch event on content View
public boolean onContentTouch(View v, MotionEvent event) {
// Do nothing if sliding is in progress
if(currentMenuState == MenuState.HIDING || currentMenuState == MenuState.SHOWING)
return false;
// getRawX returns X touch point corresponding to screen
// getX sometimes returns screen X, sometimes returns content View X
int curX = (int)event.getRawX();
int diffX = 0;
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
//Log.d("MainLayout.java onContentTouch()", "Down x " + curX);
prevX = curX;
return true;
case MotionEvent.ACTION_MOVE:
//Log.d("MainLayout.java onContentTouch()", "Move x " + curX);
// Set menu to Visible when user start dragging the content View
if(!isDragging) {
isDragging = true;
menu.setVisibility(View.VISIBLE);
}
// How far we have moved since the last position
diffX = curX - prevX;
// Prevent user from dragging beyond border
if(contentXOffset + diffX <= 0) {
// Don't allow dragging beyond left border
// Use diffX will make content cross the border, so only translate by -contentXOffset
diffX = -contentXOffset;
} else if(contentXOffset + diffX > mainLayoutWidth - menuRightMargin) {
// Don't allow dragging beyond menu width
diffX = mainLayoutWidth - menuRightMargin - contentXOffset;
}
// Translate content View accordingly
content.offsetLeftAndRight(diffX);
contentXOffset += diffX;
// Invalite this whole MainLayout, causing onLayout() to be called
this.invalidate();
prevX = curX;
lastDiffX = diffX;
return true;
case MotionEvent.ACTION_UP:
//Log.d("MainLayout.java onContentTouch()", "Up x " + curX);
Log.d("MainLayout.java onContentTouch()", "Up lastDiffX " + lastDiffX);
// Start scrolling
// Remember that when content has a chance to cross left border, lastDiffX is set to 0
if(lastDiffX > 0) {
// User wants to show menu
currentMenuState = MenuState.SHOWING;
// No need to set to Visible, because we have set to Visible in ACTION_MOVE
//menu.setVisibility(View.VISIBLE);
//Log.d("MainLayout.java onContentTouch()", "Up contentXOffset " + contentXOffset);
// Start scrolling from contentXOffset
menuScroller.startScroll(contentXOffset, 0, menu.getLayoutParams().width - contentXOffset,
0, SLIDING_DURATION);
} else if(lastDiffX < 0) {
// User wants to hide menu
currentMenuState = MenuState.HIDING;
menuScroller.startScroll(contentXOffset, 0, -contentXOffset,
0, SLIDING_DURATION);
}
// Begin querying
menuHandler.postDelayed(menuRunnable, QUERY_INTERVAL);
// Invalite this whole MainLayout, causing onLayout() to be called
this.invalidate();
// Done dragging
isDragging = false;
prevX = 0;
lastDiffX = 0;
return true;
default:
break;
}
return false;
}
}
If you want to center an item, don't use a LinearLayout as these are meant for displaying a number of items in a row.
Use a RelativeLayout instead with property android:layout_centerInParent="true"
<!-- This holds our menu -->
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<ListView
android:id="#+id/activity_main_menu_listview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#ffffff"
android:layout_centerInParent="true"
android:divider="#android:color/transparent"
android:cacheColorHint="#00000000" >
</ListView>
</RelativeLayout>
You have two problems going on.
Your parent LinearLayout is layout_width="wrap_content", which means that it only goes as far from the left edge of the screen as it needs to, not all the way to the right edge of the screen, which is what you want.
You need to tell your child ListView (activity_main_menu_listview) to center itself horizontally. The attribute you need is layout_gravity, not gravity. The layout_gravity attribute is for child views to say where within its parent it wants to be. The gravity attribute says where within the view itself (usually a TextView) the contents (usually the text) should go.
So what you need is this:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<ListView
android:id="#+id/activity_main_menu_listview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="#ffffff"
android:divider="#android:color/transparent"
android:cacheColorHint="#00000000" >
</ListView>
</LinearLayout>
Also, a couple of very minor points: 1) Google wants us to use match_parent instead of fill_parent (one of the stupidest deprecations in history); 2) You only need the xmlns attribute in the root view of the XML, not your ListView's parent.
Try this :
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical" >
And make sure your listview's item layout also have central gravity.
I noticed you also used a custom view : com.entropy.slidingmenu2.layout.MainLayout
If its not working, please post both of those code.
I have two image views, one on top of the other. Behind imageView displays user's image while the top one is cover image (just face area is fully transparent like following screenshot).
My layout is like this:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/rlContainer">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/ivUserImage"
android:contentDescription="#string/content_description"/>
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/ivCoverImage"
android:contentDescription="#string/content_description"
android:scaleType="fitXY"/>
</RelativeLayout>
I'm using OnSwipeTouchListener class in order to adjust user's shape in transparent (face) area. I have following code in onCreateView() of my fragment:
mrlContainer = (RelativeLayout) view.findViewById(R.id.rlContainer);
mUserImage = (ImageView) view.findViewById(R.id.ivUserImage);
mUserImage.setImageURI(mImgUri);
mCoverImage = (ImageView) view.findViewById(R.id.ivCoverImage);
mCoverImage.setOnTouchListener(new OnSwipeTouchListener(mContext) {
public void onSwipeTop() {
moveImageToTop();
}
public void onSwipeRight() {
moveImageToRight();
}
public void onSwipeLeft() {
moveImageToLeft();
}
public void onSwipeBottom() {
moveImageToBottom();
}
public boolean onTouch(View v, MotionEvent event) {
return getGestureDetector().onTouchEvent(event);
}
});
And my movement methods are these:
private void moveImageToTop() {
LayoutParams layoutParams = (LayoutParams) mUserImage.getLayoutParams();
layoutParams.topMargin -= 20;
mUserImage.setLayoutParams(layoutParams);
}
private void moveImageToBottom() {
LayoutParams layoutParams = (LayoutParams) mUserImage.getLayoutParams();
layoutParams.bottomMargin -= 20;
mUserImage.setLayoutParams(layoutParams);
}
private void moveImageToRight() {
LayoutParams layoutParams = (LayoutParams) mUserImage.getLayoutParams();
layoutParams.rightMargin -= 20;
mUserImage.setLayoutParams(layoutParams);
}
private void moveImageToLeft() {
LayoutParams layoutParams = (LayoutParams) mUserImage.getLayoutParams();
layoutParams.leftMargin -= 20;
mUserImage.setLayoutParams(layoutParams);
}
Now, moveImageToTop() and moveImageToBottom() are working fine when I touch screen and move my finger top or bottom. However, image scales up when I move left or right.
What you think? Where is my mistake? Any suggestion would be appreciated. Thanks
As I know, default image scaleType is FIT_CENTER. You didn't change only position since you set MATCH_PARENT in both axis. Also you change View boundaries. By changing vertical boundaries you didn't change image size inside ImageView if your image is fit in horizontal axis.
If I were you, I will use Animation framework or change position during onLayout change and ask for relayout after every swipe.
I changed xml code of behind image to following code and left/right movement fixed:
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/ivUserImage"
android:contentDescription="#string/content_description"
android:scaleType="center"/>
Anyway, I decided to use PhotoView library by chrisbanes which is very easy to use.
I have a relative layout containing three textviews, each having a width of half-width of the screen. I want the user to be able to use a scroll gesture and move these textviews together, and if the textview located far left goes off-screen, it is moved to the far right next to the third textview. So I want to create a sort of a endless scroller-system.
However, using the code below results in gaps between the views when scrolling, and I think the gap widths are dependable on the scrolling speed.
Here is a link to a screenshot of the problem: http://postimg.org/image/bnl0dqsgd/
Currently I have implemented scrolling only for one direction.
XML:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/rel_layout"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:clipChildren="false"
android:clipToPadding="false">
<com.app.healthview.BorderedTextView
android:id="#+id/btvYear1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:background="#color/YearColor1"
android:maxLines="1"
android:text="2012" />
<com.app.healthview.BorderedTextView
android:id="#+id/btvYear2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_alignParentTop="true"
android:layout_toRightOf="#+id/btvYear1"
android:background="#color/YearColor2"
android:maxLines="1"
android:text="2013" />
<com.app.healthview.BorderedTextView
android:id="#+id/btvYear3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#color/YearColor1"
android:layout_alignParentTop="true"
android:layout_toRightOf="#+id/btvYear2"
android:gravity="center"
android:maxLines="1"
android:text="2014" />
</RelativeLayout>
Then I initialize the views in a function, which is called after setting the content view:
public void InitTimeView() {
year_views = new BorderedTextView[3];
year_views[0] = (BorderedTextView) findViewById(R.id.btvYear1);
year_views[1] = (BorderedTextView) findViewById(R.id.btvYear2);
year_views[2] = (BorderedTextView) findViewById(R.id.btvYear3);
// Acquire display size
display = getWindowManager().getDefaultDisplay();
size = new Point();
display.getSize(size);
int year_width = size.x / 2;
year_views[0].setWidth(year_width);
year_views[1].setWidth(year_width);
year_views[2].setWidth(year_width);
// This is done, because when scrolling, the third view which in the beginning is off-screen, could not be seen
RelativeLayout relLayout = (RelativeLayout) findViewById(R.id.rel_layout);
relLayout.getLayoutParams().width = year_width * 4;
relLayout.invalidate();
}
Then the onScroll-method:
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
// intCurrYearMember is public, it stores the view that is next to be moved
// intRightYearMember; intCurrYearMember is located right to this view.
switch(intCurrYearMember) {
case 0:
intRightYearMember = 2;
case 1:
intRightYearMember = 0;
case 2:
intRightYearMember = 1;
}
// Move the views
for (TextView textview : year_views) {
textview.setX(textview.getX() - (distanceX / 2));
}
// Check if the view most left is now too far on left, and move it if needed to far right
if ((year_views[intCurrYearMember].getX() + year_views[intCurrYearMember].getWidth()) <= 0) {
// Is the problem here perhaps?
year_views[intCurrYearMember].setX(year_views[intRightYearMember].getRight());
intPreviousMember = intCurrYearMember;
if (intCurrYearMember < 2)
intCurrYearMember++;
else
intCurrYearMember = 0;
}
return true;
}
As it shows in the code, my idea is to build a year scroller. If someone happends to have a better, more efficient idea for how to do it, I am happy to hear your advices!
So my question is: why are there gaps between the textviews?
I would not suggest doing this at all. Utilizing Horizontal Swipes for these things is not a standard use of the platform and why waste your time developing this when there are already tested and pretty Android Components such as the Pickers that you can use easily.
A Horizontal Swiping gesture is normally saved for a Menu Drawer, View Pager, or other piece of functionality.