Android Swipe/Fling with Scrollview
by admin on Mar.24, 2011, under Research and Development
Without any more delays, here is the implementation of Swipe and ScrollView working together:
Here is the Layout:
<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:
@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):
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:
<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
Pie Graph with QT and Opengl
by admin on Nov.25, 2010, under Research and Development
This is just a simple pie graph generated with opengl, I include the code below, for everyone who want to reuse it or integrate inside some app. Is useful to visualize easily the data in real time. Feel free to download and edit according to your own needs.
DOWNLOAD
Tornado Maker
by admin on Oct.10, 2010, under Research and Development
This is just a simple Gui, aims to simplifying and automate the process of doing minimalistic tornados, basically this will change directly the variables of the algorithm to help the artist having a better control during the construction of the tornado.
Alembic the future CG interchange format
by admin on Aug.05, 2010, under General
I believe this will be a big revolution inside the industry, is suppose to be an CG interchange format focused on storing and sharing animation and VFX scenes across multiple software applications.
Due the fact is an open source project I will give all my effort to help this project going through
Fluid cloud Particles
by admin on Aug.03, 2010, under General
In this test each particle contain a fluid cloud assigned, with this technique we can experience a complete different way in how we can increase the realism of the smoke, comparison with the normal and simple particle cloud. Without raytracing each frame took me around 30sec rendering, turn on the raytracing the time increase to 9h each frame…the movie below is with raytracing on..
Particles Driven Fluids
by admin on Aug.03, 2010, under General
Now with maya2011 becomes more simple drawing fluids via particles emittion….with this technique the quality of the simulation can improve dramatically due the fact each particle will be draw inside each voxel producing more random values, colors and diferent forms of flow….
Voronoi Procedural Fracturing
by admin on Aug.03, 2010, under Research and Development
I found the “Qhull” a huge program to compute convex hulls, Voronoi diagrams and furthest-site Voronoi diagrams. the output can be used to create 3D models from the Voronoi cells.
You can see the results below: