Scrolling and Swiping in Android - android

I have layout with ViewPager and ScrollView like below:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<android.support.v4.view.ViewPager
android:id="#+id/now_playing_viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<ScrollView
android:id="#+id/lyrics_scroll_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</ScrollView>
</RelativeLayout>
Now,Textview is Scrolling as expected But on swiping viewpager is not working as it is below ScrollView.
So,when Scrolled ScrollView should work and when swiped Viewpager should.
In Short,what I want is:
moved in Y Direction--->ScrollView
moved in X Direction--->ViewPager
Code below detects that i m moving in X-direction:
public boolean onInterceptTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mLastX = event.getX();
mLastY = event.getY();
mStartX = mLastX;
break;
case MotionEvent.ACTION_MOVE:
float x = event.getX();
float y = event.getY();
float xDelta = Math.abs(x - mLastX);
float yDelta = Math.abs(y - mLastY);
float xDeltaTotal = x - mStartX;
if (xDelta > yDelta && Math.abs(xDeltaTotal) > mTouchSlop) {
// moved in X Direction
mStartX = x;
return true;
}
break;
}
return false;
}
Please help me out to achieve desired result

Related

setOnTouchListener on FloatingActionMenu Not working properly

I'm using FloatingActionMenu. In the below picture I have color the background with green color so it easy to understand the problem
I want to move the FloatingActionMenu when the user drags the pink color button. I wrote a function to move the button by getting the motion event as below
fab1.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
int action = motionEvent.getAction();
if (action == MotionEvent.ACTION_DOWN) {
downRawX = motionEvent.getRawX();
downRawY = motionEvent.getRawY();
dX = view.getX() - downRawX;
dY = view.getY() - downRawY;
return true; // not Consumed for ripple effect
} else if (action == MotionEvent.ACTION_MOVE) {
viewWidth = view.getWidth();
viewHeight = view.getHeight();
View viewParent = (View) view.getParent();
parentWidth = viewParent.getWidth();
parentHeight = viewParent.getHeight();
newX = motionEvent.getRawX() + dX;
newX = Math.max(layoutParams.leftMargin, newX); // Don't allow the FAB past the left hand side of the parent
newX = Math.min(parentWidth - viewWidth - layoutParams.rightMargin, newX); // Don't allow the FAB past the right hand side of the parent
newY = motionEvent.getRawY() + dY;
newY = Math.max(layoutParams.topMargin, newY); // Don't allow the FAB past the top of the parent
newY = Math.min(parentHeight - viewHeight - layoutParams.bottomMargin, newY); // Don't allow the FAB past the bottom of the parent
view.animate()
.x(newX)
.y(newY)
.setDuration(0)
.start();
return true; // Consumed
} else if (action == MotionEvent.ACTION_UP) {
float upRawX = motionEvent.getRawX();
float upRawY = motionEvent.getRawY();
float upDX = upRawX - downRawX;
float upDY = upRawY - downRawY;
if (newX > ((parentWidth - viewWidth - layoutParams.rightMargin) / 2)) {
newX = parentWidth - viewWidth - layoutParams.rightMargin;
} else {
newX = layoutParams.leftMargin;
}
view.animate()
.x(newX)
.y(newY)
.setInterpolator(new OvershootInterpolator())
.setDuration(300)
.start();
if (Math.abs(upDX) < CLICK_DRAG_TOLERANCE && Math.abs(upDY) < CLICK_DRAG_TOLERANCE) { // A click
if (customClickListener != null) {
customClickListener.onClick(view);
}
return false;// not Consumed for ripple effect
} else { // A drag
return false; // not Consumed for ripple effect
}
} else {
return true;
}
}
});
But It won't be working as my requirement. I want to move the button when I'm drag from the pink color button. But it moving when I drag from the green color background. Not from the pink color area. How to add touchlistener only to the round icon only?
current XML file is
<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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<com.github.clans.fab.FloatingActionMenu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:fab="http://schemas.android.com/tools"
android:id="#+id/fab_menu_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:background="#color/colorPrimary"
app:fab_colorNormal="#DA4336"
app:fab_colorPressed="#E75043"
app:fab_colorRipple="#99FFFFFF"
app:fab_shadowColor="#66000000"
app:fab_showShadow="true"
app:menu_backgroundColor="#DA4336"
app:menu_labels_colorNormal="#333333"
app:menu_labels_colorPressed="#444444"
app:menu_labels_colorRipple="#66FFFFFF"
app:menu_labels_ellipsize="end"
app:menu_labels_maxLines="-1"
app:menu_labels_position="left"
app:menu_labels_showShadow="true"
app:menu_labels_singleLine="true"
app:menu_openDirection="up">
<com.github.clans.fab.FloatingActionButton
android:id="#+id/fab_submit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/fab_add"
app:fab_label="kkjj"
app:fab_size="mini" />
<com.github.clans.fab.FloatingActionButton
android:id="#+id/fab_scan_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/fab_add"
app:fab_label="lljjl"
app:fab_size="mini" />
<com.github.clans.fab.FloatingActionButton
android:id="#+id/fab_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/fab_add"
app:fab_label="jkjkjkj"
app:fab_size="mini" />
</com.github.clans.fab.FloatingActionMenu>
</RelativeLayout>
Try to use event.getX() instead of getRawX().
Code below works for me:
// below are declared as fields
float downX;
float downY;
float dx;
float dy;
// set on touch listener
fab.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
downX = event.getX();
downY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
dx += event.getX() - downX;
dy += event.getY() - downY;
fab.setTranslationX(dx);
fab.setTranslationY(dy);
break;
case MotionEvent.ACTION_UP:
fab.performClick();
break;
}
return true;
}
});
Read your code again, seems like not only you want to drag the fab, but also you want to limit it to its parent area, so you need to do the limitation in ACTION_MOVE, by comparing the fab's bound and its parent's boundary.

OnTouch Event listener is not working after Rotation

i want to rotate a relative layout by a rotation button.
this is my code
main.java
imageContainer = (RelativeLayout)findViewById(R.id.imageContainer);
rotateBTN = (Button)findViewById(R.id.rotate);
rotateBTN.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
final float xc = imageContainer.getWidth() / 2;
final float yc = imageContainer.getHeight() / 2;
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
imageContainer.clearAnimation();
mCurrAngle = Math.toDegrees(Math.atan2(x - xc, yc - y));
break;
}
case MotionEvent.ACTION_MOVE: {
mPrevAngle = mCurrAngle;
mCurrAngle = Math.toDegrees(Math.atan2(x - xc, yc - y));
animate(mPrevAngle, mCurrAngle, 0);
break;
}
case MotionEvent.ACTION_UP : {
rotate = false;
mPrevAngle = mCurrAngle = 0;
break;
}
}
return true;
}
});
private void animate(double fromDegrees, double toDegrees, long durationMillis) {
final RotateAnimation rotate = new RotateAnimation((float) fromDegrees, (float) toDegrees,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
rotate.setDuration(durationMillis);
rotate.setFillEnabled(true);
rotate.setFillAfter(true);
imageContainer.startAnimation(rotate);
// imageView2.startAnimation(rotate);
System.out.println(mCurrAngle);
}
main.xml
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:id="#+id/onlyImage"
android:layout_marginTop="20dp">
<ImageView
android:id="#+id/imageView1"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="#drawable/ic_launcher"
/>
<ImageView
android:id="#+id/imageView2"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="#drawable/ic_launcher"
android:visibility="gone"
/>
</RelativeLayout>
<Button
android:layout_width="30dp"
android:layout_height="30dp"
android:id="#+id/rotate"
/>
</RelativeLayout>
by this code, i am able to rotate the RelativeLayout. But the problem is that after rotating first time (rotate button also rotates because it is inside my RelativeLayout) ontouch event is not called on new position of my rotate button but if i touch the top left corner of my relative layout ( initial position of my button) onTouch listener works fine.
plz help me find the issue. any suggestion would be appreciated :)
this is my relative layout
P.S i want to do something like this

Make two ImageViews coincident zooming

I have two ImageViews on a layout file:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent"
android:id="#+id/root">
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/zoom" />
<ImageView
android:layout_width="55dp"
android:layout_height="55dp"
android:id="#+id/drag"
android:layout_gravity="center_horizontal|top"
android:layout_alignParentTop="false" />
</RelativeLayout>
The ImageView with id zoom has implemented the PhotoViewAttacher which makes the ImageView zoomable.
The other ImageView with id = drag has a OnTouchListener:
drag.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
final int X = (int) event.getRawX();
final int Y = (int) event.getRawY();
//Definition MotionEvent.ACTION_MASK: Bit mask of the parts of the action code that are the action itself.
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) v.getLayoutParams();
int i = lParams.leftMargin;
_xDelta = X - lParams.leftMargin;
_yDelta = Y - lParams.topMargin;
break;
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_POINTER_DOWN:
break;
case MotionEvent.ACTION_POINTER_UP:
break;
case MotionEvent.ACTION_MOVE:
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) v
.getLayoutParams();
layoutParams.leftMargin = X - _xDelta;
layoutParams.topMargin = Y - _yDelta;
layoutParams.rightMargin = -250;
layoutParams.bottomMargin = -250;
v.setLayoutParams(layoutParams);
break;
}
viewGroup.invalidate();
return true;
}
});
So the drag ImageView is moveable around the screen.
What I want is: If I zoom in, the drag ImageView shall be zoomed in too. Same the other way while zooming out.
How can I place the drag ImageView in a way that it is "docked" on the zoom ImageView. So if I move the zoom image around the screen, the drag image have to stay on the position it left.
For example:
drag is moved to center of the screen.
zoom is zoomed in
zoom moved to right so the drag image is moved outside the screen
zoom moved back to the center where the drag image is docked
I hope you understand what I want to do
Kind Regards!!

How to use over scroll mode in Android

Problem
I need to give some priority for scrolling events in my Activity.
I'm using aiCharts (charts library) and I need to zoom, pan, etc. on my areas. Without any ScrollViews it works fine, but, if I use the mentioned Layout, these features works bad. I think because of priority of views.
Possible solution
I tried to use setOverScrollMode(View.OVER_SCROLL_ALWAYS); on views that need to be on "top" of ScrollView and HorizontalScrollView but doesn't work properly.
Layout
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<RelativeLayout
android:id="#+id/screen_relative_layout"
android:layout_width="wrap_content"
android:layout_height="match_parent" >
</RelativeLayout>
</HorizontalScrollView>
</ScrollView>
All my views are added programmatically by adding to RelativeLayout.
Change your RelativeLayout so that the android:layout_height="wrap_content"
Also do your own custom scrollview so that it intercepts the movement and nothing else:
public class VerticalScrollView extends ScrollView {
private float xDistance, yDistance, lastX, lastY;
public VerticalScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
xDistance = yDistance = 0f;
lastX = ev.getX();
lastY = ev.getY();
break;
case MotionEvent.ACTION_MOVE:
final float curX = ev.getX();
final float curY = ev.getY();
xDistance += Math.abs(curX - lastX);
yDistance += Math.abs(curY - lastY);
lastX = curX;
lastY = curY;
if(xDistance > yDistance)
return false;
}
return super.onInterceptTouchEvent(ev);
}
}
source
Let me know how that worked!

stop touch from passing to lower surfaceview

I have a SurfaceView "over" a GLSurfaceView in Android.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<my.project.ActionSurface
android:id="#+id/actionSurface"
android:layout_marginBottom="30dip"
android:layout_marginLeft="20dip"
android:layout_marginRight="20dip"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
/>
<fi.harism.curl.CurlView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/larryMoeCurly"
/>
</RelativeLayout>
(Many thanks to harism for his page curl code!)
In my ActionSurface, I have this to detect touches:
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
newX = (int) event.getX();
newY = (int) event.getY();
diffX = newX - x;
diffY = newY - y;
Log.d(TAG, "touched at x:" + newX + " y:" + newY);
}
return true;
}
When I touch my ActionSurface, it responds correctly, but the touch goes through to the CurlView as well. How do I stop the touch from "passing through" to the other surface?
you could add an OnTouchListener to your surface view, and catch the event there (return true):
this.setOnTouchListener(new View.OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent event)
{
return true;
}
});

Categories

Resources