6

enter image description here
I am creating a Relative Layout and want to add click as well as swipe(touch and move pointer over the layout to move it in real time) and detect left and right swipe. I have tried the following code so far.

public bool OnTouch(View v, MotionEvent e)
    {
        if (gestureDetector.OnTouchEvent(e))
        {
            //This is a Click
            return true;
        }
        else
        {
            int initialTouchX = 0, initialTouchY = 0;
            int newx = 0;
            var x = v.Left;
            switch (e.Action)
            {

                case MotionEventActions.Down:
                    {
                        _viewX = e.GetX();
                        _viewY = e.GetY();
                        initialTouchX = (int)e.RawX;
                        initialTouchY = (int)e.RawY;
                        break;
                    }

                case MotionEventActions.Move:
                    {

                        var left = (int)(e.RawX - _viewX);
                        newx = left;
                        var right = (int)(left + v.Width);

                        var top = (int)(e.RawY - _viewY);
                        var bottom = (int)(top + v.Height);

                        v.Layout(left, top, right, bottom);

                        break;
                    }
                case MotionEventActions.Up:
                    {
                        int lastX = (int)e.GetX();
                        int lastY = (int)e.GetY();
                       if ((x - newx) > 40)
                        {
                          //Detect Right Swipe

                        }
                        else if ((newx - x > 40))
                        {
            //Detect Left Swipe
                        }
                        else
                        {
                            //Skip others
                        }
        break;
                    }

            }
        }
        return true;
    }

My code for gestureDetector.OnTouchEvent(e)

gestureDetector = new GestureDetector(this, new SingleTapUp());

class SingleTapUp : Android.Views.GestureDetector.SimpleOnGestureListener 
    {

        public override bool OnSingleTapUp(MotionEvent e) {
           // Toast.MakeText(this,, ToastLength.Long).Show();
            return true;
        }

    }

My code is working fine on some devices as well as emulator. But not working sometimes and onclick the layout moves automatically(The layout out centers itself at touch pointer). I think something is wrong and causing the issue. You can suggest me the best/standard way to do it. Any help will be greatly appreciated.

  • the touch events are on a specific object or in the whole layout? – CDrosos Oct 10 '15 at 06:43
  • On the whole relative layout. – soumya sambit Kunda Oct 10 '15 at 06:45
  • so for example we have an image in the background and the whole relative layout that is changing with swype and somewhere also we have a static button in the layout? – CDrosos Oct 10 '15 at 06:47
  • No The whole relative layout should respond to the click take for an example an item in a listview. The way selection changed event works on it I want it that way. And my code works upto some extent. – soumya sambit Kunda Oct 10 '15 at 06:55
  • I am achieving it in this way gestureDetector = new GestureDetector(this, new SingleTapUp()); viewObj.SetOnTouchListener(this); – soumya sambit Kunda Oct 10 '15 at 06:56
  • @CDrosos here viewObj is my whole layout – soumya sambit Kunda Oct 10 '15 at 06:56
  • how you combine swype and onclick and moving events? you want to drag items from a listview for example? how your app works? – CDrosos Oct 10 '15 at 07:11
  • My app constists of some relativelayout placed one over the other the user should be able to swipe the layout(push the top to back) and click on the top layout. It is a rss reader app – soumya sambit Kunda Oct 10 '15 at 07:19
  • @CDrosos I have added a screenshot in question – soumya sambit Kunda Oct 10 '15 at 07:25
  • oh i see, so you need the whole layout to be moveable and when it is dragged to be flipped on the back? I think the best solution for what you want is a ViewPager with a custom transition animation – CDrosos Oct 10 '15 at 07:37
  • @CDrosos I have to use the relative layout only because I have to rework for that and I am beginner to android. In my code I have done the part but only facing problem on click sometime – soumya sambit Kunda Oct 10 '15 at 07:44
  • how do you define onclick for the next layout? – CDrosos Oct 10 '15 at 08:19
  • @CDrosos I am just adding the onclick listener to every controler dynamically – soumya sambit Kunda Oct 10 '15 at 15:08
  • maybe you should post your removal layout and the onlcik listener assign code – CDrosos Oct 10 '15 at 15:12
  • I am adding the ontouchlistener to all my layouts. and upon swipe I am sending view to back its doing my stuff :) – soumya sambit Kunda Oct 10 '15 at 15:14
  • ok i understand :), maybe you should make sure that the previous layout is gone/ destroyed before assign the onclick event with an async / await task – CDrosos Oct 10 '15 at 15:15
  • @CDrosos can you give me some light to achieve it – soumya sambit Kunda Oct 10 '15 at 15:47
  • how you are removing/moving to back stack a current layout? – CDrosos Oct 10 '15 at 15:50
  • public void sendViewToBack(View child) { var parent = (ViewGroup)child.Parent; if (null != parent) { parent.RemoveView(child); if(viewType==0) parent.AddView(QueueListView (theNewsQueue), 0); else parent.AddView(QueueListView (theNewsQueue), parent.ChildCount-1); // child.Visibility = ViewStates.Gone; } – soumya sambit Kunda Oct 10 '15 at 15:51
  • your code is good, i don't know why you get this behavior :( , maybe try to set a small delay after the addition of the view before the onclick assign and see if this change anything – CDrosos Oct 10 '15 at 16:03
  • Thank for giving your valuable time :) – soumya sambit Kunda Oct 10 '15 at 16:06
  • my pleasure, sorry if i wasn't useful – CDrosos Oct 10 '15 at 16:15
  • @CDrosos can you give some idea how to overlap pages in viewpager :) – soumya sambit Kunda Oct 13 '15 at 07:12
  • :) i have update my answer, please tell me if this is what you need – CDrosos Oct 13 '15 at 14:30
  • @CDrosos your help(with the updated code) is leading me to achieve my requirement. One last thing How to show multiple pages as per my screenshot :) – soumya sambit Kunda Oct 13 '15 at 14:47
  • Here is a very good article on how you can show the next and previous items on a ViewPager http://blog.neteril.org/blog/2013/10/14/android-tip-viewpager-with-protruding-children/ but im not sure if you can modify it to show the images as you want. if i think of something else i will post again – CDrosos Oct 13 '15 at 15:00
  • check also this question here with my blog post also http://stackoverflow.com/questions/10001503/android-carousel-like-widget-which-displays-a-portion-of-the-left-and-right-el what it says is this: "The ViewPager has a method called setPageMargin(). This method can receive a negative value which will make the fragments/views to overlap each other." i think this is your best bet to gain what you want :) – CDrosos Oct 14 '15 at 18:32
  • check the end of the updated answer for ideas to overlap pages and give them a rotated effect – CDrosos Oct 14 '15 at 18:40
  • did you manage to do it? :) – CDrosos Oct 21 '15 at 19:31

1 Answers1

3

Im implementing swype in this way:

public class MainActivity : Activity, GestureDetector.IOnGestureListener
{
private GestureDetector _gestureDetector;

public bool OnDown(MotionEvent e)
    {
        return false;
    }
    public bool OnFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
    {
        bool result = false;
        int SWIPE_THRESHOLD = 80;
        int SWIPE_VELOCITY_THRESHOLD = 80;
        try
        {
            float diffY = e2.GetY() - e1.GetY();
            float diffX = e2.GetX() - e1.GetX();
            if (Math.Abs(diffX) > Math.Abs(diffY))
            {
                if (Math.Abs(diffX) > SWIPE_THRESHOLD && Math.Abs(velocityX) > SWIPE_VELOCITY_THRESHOLD)
                {
                    if (diffX > 0)
                    {
                        //code for swipe right here

                    }
                    else
                    {
                        //code for swipe Left here

                    }
                }
            }
        }
        catch (Exception exception)
        {
            //exception.printStackTrace();
        }
        return result;
    }
    public void OnLongPress(MotionEvent e) {}
    public bool OnScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
    {
        return false;
    }
    public void OnShowPress(MotionEvent e) {}
    public bool OnSingleTapUp(MotionEvent e)
    {
        return false;
    }
public override bool OnTouchEvent(MotionEvent e)
    {
        _gestureDetector.OnTouchEvent(e);
        return false;
    }

    protected override void OnCreate (Bundle bundle)
    {
        base.OnCreate (bundle);

        SetContentView (Resource.Layout.Main);
        _gestureDetector = new GestureDetector(this);

    }
}

For ViewPager you can overlap Pages with something like this PageTransformation:

using System;

using Android.Views;
using Android.Support.V4.View;

namespace SomeName
{
public class SinkAndSlideTransformer : Java.Lang.Object, ViewPager.IPageTransformer
{
public void TransformPage(View view, float position)
{
if (position < -1 || position > 1) 
{
view.Alpha = 0; // The view is offscreen.
} 
else
{
view.Alpha = 1;

if (position < 0) 
{
// 'Sink' the view if it's to the left.
// Scale the view.
view.ScaleX = 1 - Math.Abs (position);
view.ScaleY = 1 - Math.Abs (position);

// Set the translationX to keep the view in the middle.
view.TranslationX = view.Width * Math.Abs (position);
} 
}
}
}
}

Which will give this effect:
enter image description here

With this Adapter:

using System;
using System.Collections.Generic;

using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using Android.Support.V4.View;

using Square.Picasso;

namespace StaffPro
{
public class SlideshowPagerAdapter : PagerAdapter
{
    List<Uri> _items = new List<Uri>();
    private readonly Activity _context;

    public SlideshowPagerAdapter (Activity context, List<Uri> items) : base()
    {
        _items = items;
        _context = context;
    }
    public override int Count 
    {
        get { return _items.Count; }
    }
    public override bool IsViewFromObject(View view, Java.Lang.Object _object) 
    {
        return view == ((RelativeLayout) _object);
    }
    public override Java.Lang.Object InstantiateItem(ViewGroup container, int position)
    {
        var view = LayoutInflater.From (container.Context).Inflate (Resource.Layout.SlideshowViewPager, container, false);
        ImageView imageView = view.FindViewById<ImageView> (Resource.Id.slideshowImageView);
        Picasso.With(_context).Load(_items [position].ToString()).Into(imageView);
        container.AddView(view);

        return view;
    }
    public override void DestroyItem(ViewGroup container, int position, Java.Lang.Object _object)
    {
        container.RemoveView((View)_object);
    }
}
}

And to call the viewpages and the adapter with something like this:

var viewPagerAdapter = new SlideshowPagerAdapter(Activity, some_Uri_images);
        slideshowViewPager.Adapter = viewPagerAdapter;
        slideshowViewPager.SetPageTransformer (true, new SinkAndSlideTransformer ());

More Transformations you can find here.

Also keep in mind that the ViewPager has a method called setPageMargin(). This method can receive a negative value which will make the fragments/views to overlap each other.
You can also use view.Rotation inside your Transformation code to implement the photo randomly dropped and overlapped effect you want.
If you need to retain many images loaded and displayed check also ViewPager.OffscreenPageLimit it will override the default cache limit of storing pages for the next and previous item, be careful about high memory usage however.

CDrosos
  • 2,418
  • 4
  • 26
  • 49