João Machete

Tag: java

Android Swipe/Fling with Scrollview

by on Mar.24, 2011, under Research and Development

flingandscroll

Without any more delays, here is the implementation of Swipe and ScrollView working together:

Here is the Layout:

<?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">
    <TextView android:layout_width="fill_parent"
        android:layout_height="wrap_content" android:text="@string/hello"
        android:gravity="center" />
 <com.machete.FlingAndScrollViewer.FlingAndScrollViewer
        android:layout_width="fill_parent" android:layout_height="fill_parent"
        android:id="@+id/flingScrollViewer">
        <ScrollView android:id="@+id/scrollView1"
            android:background="#FF8000" android:layout_height="fill_parent"
            android:layout_width="fill_parent">
            <LinearLayout android:id="@+id/linearLayout1"
                android:layout_height="fill_parent" android:layout_width="fill_parent"
                android:orientation="vertical">
                <TextView android:id="@+id/TextView01" android:text="1"
                    android:textColor="#ffffff" android:layout_width="fill_parent"
                    android:layout_weight="1" android:gravity="center"
                    android:layout_height="wrap_content" android:textSize="500dip"></TextView>
            </LinearLayout>
        </ScrollView>
     <ScrollView android:id="@+id/scrollView2"
            android:background="#0080FF" android:layout_height="fill_parent"
            android:layout_width="fill_parent">
            <LinearLayout android:id="@+id/linearLayout2"
                android:layout_height="fill_parent" android:layout_width="fill_parent"
                android:orientation="vertical">
                <TextView android:id="@+id/TextView02" android:text="2"
                    android:textColor="#ffffff" android:layout_width="fill_parent"
                    android:layout_weight="1" android:gravity="center"
                    android:layout_height="wrap_content" android:textSize="500dip"></TextView>
            </LinearLayout>
        </ScrollView>
     <ScrollView android:id="@+id/scrollView3"
            android:background="#00FF00" android:layout_height="fill_parent"
            android:layout_width="fill_parent">
            <LinearLayout android:id="@+id/linearLayout3"
                android:layout_height="fill_parent" android:layout_width="fill_parent"
                android:orientation="vertical">
                <TextView android:id="@+id/TextView03" android:text="3"
                    android:textColor="#ffffff" android:layout_width="fill_parent"
                    android:layout_weight="1" android:gravity="center"
                    android:layout_height="wrap_content" android:textSize="500dip"></TextView>
            </LinearLayout>
        </ScrollView>
 </com.machete.FlingAndScrollViewer.FlingAndScrollViewer>
</LinearLayout>

Here is the Main Activity:

public class Main  extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        FlingAndScrollViewer flingAndScrollViewer =
        (FlingAndScrollViewer) findViewById(R.id.flingScrollViewer);
        flingAndScrollViewer.setInitialPosition(0); //set the initial position
    }
}

As you can see with our setInitialPosition we are able to define the startup.

Here is our custom View(the trick):

public class FlingAndScrollViewer extends ViewGroup {
    private Scroller mScroller;
    private VelocityTracker mVelocityTracker;
    private int mScrollX = 0;
    private int mCurrentScreen = 0;
    private float mLastMotionX;
    private static final String LOG_TAG = "FlingAndScrollViewer";
    private static final int SNAP_VELOCITY = 1000;
    private final static int TOUCH_STATE_REST = 0;
    private final static int TOUCH_STATE_SCROLLING = 1;
    private int mTouchState = TOUCH_STATE_REST;
    private int mTouchSlop = 0;

    public FlingAndScrollViewer(Context context) {
        super(context);
        mScroller = new Scroller(context);
        mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
        this.setLayoutParams(new ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.FILL_PARENT));
    }

    public FlingAndScrollViewer(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray a = getContext().obtainStyledAttributes(attrs,
                R.styleable.FlingAndScrollViewer);
        mCurrentScreen = a.getInteger(
                R.styleable.FlingAndScrollViewer_default_screen, 0);
        mScroller = new Scroller(context);
        mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
        this.setLayoutParams(new ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.FILL_PARENT));
    }

    public void setInitialPosition(int initialPosition) {
        mCurrentScreen = initialPosition;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        /*
         * This method JUST determines whether we want to intercept the motion.
         * If we return true, onTouchEvent will be called and we do the actual
         * scrolling there.
         */

     /*
         * Shortcut the most recurring case: the user is in the dragging state
         * and he is moving his finger. We want to intercept this motion.
         */

        final int action = ev.getAction();
        if ((action == MotionEvent.ACTION_MOVE)
                , (mTouchState != TOUCH_STATE_REST)) {
            return true;
        }
     final float x = ev.getX();
     switch (action) {
        case MotionEvent.ACTION_MOVE:
            /*
             * mIsBeingDragged == false, otherwise the shortcut would have
             * caught it. Check whether the user has moved far enough from his
             * original down touch.
             */

         /*
             * Locally do absolute value. mLastMotionX is set to the y value of
             * the down event.
             */

            final int xDiff = (int) Math.abs(x - mLastMotionX);
         boolean xMoved = xDiff > mTouchSlop;
         if (xMoved) {
                // Scroll if the user moved far enough along the X axis
                mTouchState = TOUCH_STATE_SCROLLING;
            }
            break;
     case MotionEvent.ACTION_DOWN:
            // Remember location of down touch
            mLastMotionX = x;
         /*
             * If being flinged and user touches the screen, initiate drag;
             * otherwise don't. mScroller.isFinished should be false when being
             * flinged.
             */

            mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST
                    : TOUCH_STATE_SCROLLING;
            break;
     case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP:
            // Release the drag
            mTouchState = TOUCH_STATE_REST;
            break;
        }
     /*
         * The only time we want to intercept motion events is if we are in the
         * drag mode.
         */

        return mTouchState != TOUCH_STATE_REST;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
     if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        }
        mVelocityTracker.addMovement(event);
     final int action = event.getAction();
        final float x = event.getX();
     switch (action) {
        case MotionEvent.ACTION_DOWN:
            Log.i(LOG_TAG, "event : down");
            /*
             * If being flinged and user touches, stop the fling. isFinished
             * will be false if being flinged.
             */

            if (!mScroller.isFinished()) {
                mScroller.abortAnimation();
            }
         // Remember where the motion event started
            mLastMotionX = x;
            break;
        case MotionEvent.ACTION_MOVE:
            // Log.i(LOG_TAG,"event : move");
            // if (mTouchState == TOUCH_STATE_SCROLLING) {
            // Scroll to follow the motion event
            final int deltaX = (int) (mLastMotionX - x);
            mLastMotionX = x;
         // Log.i(LOG_TAG, "event : move, deltaX " + deltaX + ", mScrollX " +
            // mScrollX);
         if (deltaX < 0) {
                if (mScrollX > 0) {
                    scrollBy(Math.max(-mScrollX, deltaX), 0);
                }
            } else if (deltaX > 0) {
                final int availableToScroll = getChildAt(getChildCount() - 1)
                        .getRight() - mScrollX - getWidth();
                if (availableToScroll > 0) {
                    scrollBy(Math.min(availableToScroll, deltaX), 0);
                }
            }
            // }
            break;
        case MotionEvent.ACTION_UP:
            Log.i(LOG_TAG, "event : up");
            // if (mTouchState == TOUCH_STATE_SCROLLING) {
            final VelocityTracker velocityTracker = mVelocityTracker;
            velocityTracker.computeCurrentVelocity(1000);
            int velocityX = (int) velocityTracker.getXVelocity();
         if (velocityX > SNAP_VELOCITY , mCurrentScreen > 0) {
                // Fling hard enough to move left
                snapToScreen(mCurrentScreen - 1);
            } else if (velocityX < -SNAP_VELOCITY
                    , mCurrentScreen < getChildCount() - 1) {
                // Fling hard enough to move right
                snapToScreen(mCurrentScreen + 1);
            } else {
                snapToDestination();
            }
         if (mVelocityTracker != null) {
                mVelocityTracker.recycle();
                mVelocityTracker = null;
            }
            // }
            mTouchState = TOUCH_STATE_REST;
            break;
        case MotionEvent.ACTION_CANCEL:
            Log.i(LOG_TAG, "event : cancel");
            mTouchState = TOUCH_STATE_REST;
        }
        mScrollX = this.getScrollX();
     return true;
    }

    private void snapToDestination() {
        final int screenWidth = getWidth();
        final int whichScreen = (mScrollX + (screenWidth / 2)) / screenWidth;
        Log.i(LOG_TAG, "from des");
        snapToScreen(whichScreen);
    }

    public void snapToScreen(int whichScreen) {
        Log.i(LOG_TAG, "snap To Screen " + whichScreen);
        mCurrentScreen = whichScreen;
        final int newX = whichScreen * getWidth();
        final int delta = newX - mScrollX;
        mScroller.startScroll(mScrollX, 0, delta, 0, Math.abs(delta) * 2);
        invalidate();
    }

    public void setToScreen(int whichScreen) {
        Log.i(LOG_TAG, "set To Screen " + whichScreen);
        mCurrentScreen = whichScreen;
        final int newX = whichScreen * getWidth();
        mScroller.startScroll(newX, 0, 0, 0, 10);
        invalidate();
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int childLeft = 0;
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child.getVisibility() != View.GONE) {
                final int childWidth = child.getMeasuredWidth();
                child.layout(childLeft, 0, childLeft + childWidth,
                        child.getMeasuredHeight());
                childLeft += childWidth;
            }
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        final int width = MeasureSpec.getSize(widthMeasureSpec);
        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        if (widthMode != MeasureSpec.EXACTLY) {
            throw new IllegalStateException("error mode.");
        }
        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        if (heightMode != MeasureSpec.EXACTLY) {
            throw new IllegalStateException("error mode.");
        }
        // The children are given the same width and height as the workspace
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
        }
        Log.i(LOG_TAG, "moving to screen " + mCurrentScreen);
        scrollTo(mCurrentScreen * width, 0);
    }

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            mScrollX = mScroller.getCurrX();
            scrollTo(mScrollX, 0);
            postInvalidate();
        }
    }

    /**
     * Return the parceable instance to be saved
     */

    @Override
    protected Parcelable onSaveInstanceState() {
        final SavedState state = new SavedState(super.onSaveInstanceState());
        state.currentScreen = mCurrentScreen;
        return state;
    }

    /**
     * Restore the previous saved current screen
     */

    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        SavedState savedState = (SavedState) state;
        super.onRestoreInstanceState(savedState.getSuperState());
        if (savedState.currentScreen != -1) {
            mCurrentScreen = savedState.currentScreen;
        }
    }

    // ========================= INNER CLASSES ==============================
    public interface onViewChangedEvent {
        void onViewChange(int currentViewIndex);
    }

    /**
     * A SavedState which save and load the current screen
     */

    public static class SavedState extends BaseSavedState {
        int currentScreen = -1;

        /**
         * Internal constructor
         *
         * @param superState
         */

        SavedState(Parcelable superState) {
            super(superState);
        }

        /**
         * Private constructor
         *
         * @param in
         */

        private SavedState(Parcel in) {
            super(in);
            currentScreen = in.readInt();
        }

        /**
         * Save the current screen
         */

        @Override
        public void writeToParcel(Parcel out, int flags) {
            super.writeToParcel(out, flags);
            out.writeInt(currentScreen);
        }

        /**
         * Return a Parcelable creator
         */

        public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() {
            public SavedState createFromParcel(Parcel in) {
                return new SavedState(in);
            }

            public SavedState[] newArray(int size) {
                return new SavedState[size];
            }
        };
    }
}

To finalize this, create a attrs.xml inside yours res/values:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="FlingAndScrollViewer">
        <attr name="default_screen" format="integer"/>
    </declare-styleable>
</resources>

That is it, now you can swipe between pages and scroll in any direction you want

6 Comments :, more...

EnaOCR – Open Source

by on Mar.25, 2010, under Research and Development

This is another contribution to the world of open source. I started developing this project in the university, and I will continue to work on it until it is stable enough to run on any operating system. For now only runs in Windows and Linux. OSX is the next step, I hope this can be available soon.
splashWhat is EnaOCR?

EnaOCR is a Optical Character Recognition desktop application, that allows you to read multiple images files and convert them to ASCII text or XML.

With this application is easy to deploy any data to any external database in a short period of time. You just need one click to process hundreds of images in seconds, is very fast and with strong accuracy in the detection of words

(continue reading…)

2 Comments :, more...

Replace backslash character to slash in a String with JAVA

by on Aug.20, 2009, under General

Today I had a small problem with java, and I leave here my solution to help others who are in the same situation.

Here I give you a small trick to replace backslash special caracter to another caracter in Java. If you are doing some project, and you need to replace a backslash “\” with the forward slash “/”, you will notice you can´t do this in the normal way.

Let´s see “the normal way”:

String address = "C:\Program Files\Java\jre6"
address = address.replace("\" , "/"):

you will have a error.

try this….

String address = "C:\Program Files\Java\jre6"
String backslash= System.getProperty("file.separator") ;
address= address.replace(backslash,"/");
System.out.println(address);

OUTPUT:

C:/Program Files/Java/jre6

;)

inputPath = inputPath.replace(barra,”/”);
System.out.println(inputPath)
3 Comments : more...

First Time with GWT

by on Feb.03, 2009, under Research and Development

This tutorial introduces you to GWT. You can do develop GWT apps without any IDE, but it is really helpful if you use one. I choose Eclipse with Cypal Studio for GWT (which was earlier known as Googlipse) to walk thru this tutorial.

Requirements:

  • You need the latest GWT. You can download it at here. Make sure you download the latest version.
  • Download and install Eclipse 3.4 with WTP 2.0. You can get it here.
  • You need a Java 1.5 VM to run Eclipse. You can get it here.
  • Download Cypal Studio for GWT from here and extract it to your eclipse directory.

(continue reading…)

Leave a Comment :, more...

Install Google Web Toolkit in Ubuntu

by on Feb.03, 2009, under General

#!/bin/bash

wget http://google-web-toolkit.googlecode.com/files/gwt-linux-1.5.3.tar.bz2 -P /tmp
tar xjf /tmp/gwt-linux-1.5.3.tar.bz2 -C /tmp
sudo mv /tmp/gwt-linux-1.5.3 /opt/gwt-linux

3 Comments :, more...

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!