Saturday, 23 May 2015

sliding panel android example, slider left to right

No comments
In this example we learn,how to create programmatic sliding panel or slider from left to right.
In sliding Panel,hold content and allow user to slide the content on demand. 

Its very helpful while we need big screen space.in this example, very simple approach to create a Sliding Panel Is just like a View Switcher in which first child work as sliding Panel.

CREATE NEW PROJECT:

Step 1: Write code into activity_main.xml

<dev.EmprovantionTechsol.slider.SlideHolder xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/slideHolder"
    android:layout_width="fill_parent"
    android:layout_height="match_parent"
    android:background="#2988FE"
    android:orientation="vertical"
    tools:context=".MainActivity" >

Here,First layout considered as a sliding panel e.g.ScrollView.


    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="fill_parent"
        android:layout_marginRight="50dp"
        android:background="#BC7CFE" >
    
    <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:orientation="vertical" >
     
       <TextView
                android:id="@+id/textView1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="14dp"
                android:text="swipe right to left"
                android:textSize="25sp" />
  
          <TextView
                android:id="@+id/textView2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="14dp"
                android:text="swipe right to left"
                android:textSize="25sp" />
   
         <TextView
                android:id="@+id/textView3"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="14dp"
                android:text="swipe right to left"
                android:textSize="25sp" />
   
         <TextView
                android:id="@+id/textView4"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="14dp"
                android:text="swipe right to left"
                android:textSize="25sp" />
  
          <TextView
                android:id="@+id/textView5"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="14dp"
                android:text="swipe right to left"
                android:textSize="25sp" />
   
         <TextView
                android:id="@+id/textView6"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="14dp"
                android:text="swipe right to left"
                android:textSize="25sp" />
   
         <TextView
                android:id="@+id/textView7"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="14dp"
                android:text="swipe right to left"
                android:textSize="25sp" />
   
         <TextView
                android:id="@+id/textView8"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="14dp"
                android:text="swipe right to left"
                android:textSize="25sp" />
   
         <TextView
                android:id="@+id/textView9"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="14dp"
                android:text="swipe right to left"
                android:textSize="25sp" />
    
        <TextView
                android:id="@+id/textView10"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="14dp"
                android:text="swipe right to left"
                android:textSize="25sp" />
    
        <TextView
                android:id="@+id/textView11"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="14dp"
                android:text="swipe right to left"
                android:textSize="25sp" />
    
        <TextView
                android:id="@+id/textView12"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="14dp"
                android:text="swipe right to left"
                android:textSize="25sp" />
 
       </LinearLayout>
    </ScrollView>

    <RelativeLayout
        android:id="@+id/RelativeLayout1"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:gravity="bottom" >
  
     <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_centerHorizontal="true"
            android:layout_marginBottom="14dp"
            android:text="swipe left to right"
            android:textSize="25sp" />
    </RelativeLayout>
</dev.EmprovantionTechsol.slider.SlideHolder>



Now we need two java file 1).MainActivity.java and 2).SliderHolder.java.


SliderHolder.java is use to hold contain in a Sliding panel.

Step 2: Write code into MainActivity.java

package dev.EmprovantionTechsol.slider;

import android.os.Bundle;

import android.app.Activity;
import android.view.Menu;

public class MainActivity extends Activity {

private SlideHolder mSlideHolder;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

mSlideHolder = (SlideHolder) findViewById(R.id.slideHolder);
}

@Override

public boolean onCreateOptionsMenu(Menu menu) {

// Inflate the menu; this adds items to the action bar if it is present.

getMenuInflater().inflate(R.menu.main, menu);
return true;
}


}


Step 3: Write code into SlideHolder.java

package dev.EmprovantionTechsol.slider;

import java.util.LinkedList;
import java.util.Queue;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.Rect;
import android.graphics.Region.Op;
import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Transformation;
import android.widget.FrameLayout;

public class SlideHolder extends FrameLayout {



public final static int DIRECTION_LEFT = 1;
public final static int DIRECTION_RIGHT = -1;

protected final static int MODE_READY = 0;
protected final static int MODE_SLIDE = 1;
protected final static int MODE_FINISHED = 2;

private Bitmap mCachedBitmap;
private Canvas mCachedCanvas;
private Paint mCachedPaint;
private View mMenuView;

private int mMode = MODE_READY;
private int mDirection = DIRECTION_LEFT;

private int mOffset = 0;
private int mStartOffset;
private int mEndOffset;

private boolean mEnabled = true;
private boolean mInterceptTouch = true;
private boolean mAlwaysOpened = false;
private boolean mDispatchWhenOpened = false;

private Queue<Runnable> mWhenReady = new LinkedList<Runnable>();

private OnSlideListener mListener;

public SlideHolder(Context context) {
super(context);

initView();
}

public SlideHolder(Context context, AttributeSet attrs) {
super(context, attrs);

initView();
}

public SlideHolder(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);

initView();
}

private void initView() {
mCachedPaint = new Paint(
Paint.ANTI_ALIAS_FLAG
| Paint.FILTER_BITMAP_FLAG
| Paint.DITHER_FLAG
);
}

@Override
public void setEnabled(boolean enabled) {
mEnabled = enabled;
}

@Override
public boolean isEnabled() {
return mEnabled;
}

/**

* direction - direction in which SlideHolder opens. Can be: DIRECTION_LEFT, DIRECTION_RIGHT
*/
public void setDirection(int direction) {
closeImmediately();

mDirection = direction;
}

/**

* allow - if false, SlideHolder won't react to swiping gestures 
*/
public void setAllowInterceptTouch(boolean allow) {
mInterceptTouch = allow;
}

public boolean isAllowedInterceptTouch() {
return mInterceptTouch;
}

/**

* @param dispatch - if true, in open state SlideHolder will dispatch touch events to main layout (in other words - it will be clickable)
*/
public void setDispatchTouchWhenOpened(boolean dispatch) {
mDispatchWhenOpened = dispatch;
}

public boolean isDispatchTouchWhenOpened() {
return mDispatchWhenOpened;
}

/**

* opened - if true, SlideHolder will always be in opened state.
*/
public void setAlwaysOpened(boolean opened) {
mAlwaysOpened = opened;

requestLayout();
}

public int getMenuOffset() {
return mOffset;
}

public void setOnSlideListener(OnSlideListener lis) {
mListener = lis;
}

public boolean isOpened() {
return mAlwaysOpened || mMode == MODE_FINISHED;
}

public void toggle(boolean immediately) {
if(immediately) {
toggleImmediately();
} else {
toggle();
}
}

public void toggle() {
if(isOpened()) {
close();
} else {
open();
}
}

public void toggleImmediately() {
if(isOpened()) {
closeImmediately();
} else {
openImmediately();
}
}

public boolean open() {
if(isOpened() || mAlwaysOpened || mMode == MODE_SLIDE) {
return false;
}

if(!isReadyForSlide()) {
mWhenReady.add(new Runnable() {

@Override
public void run() {
open();
}
});

return true;
}

initSlideMode();

Animation anim = new SlideAnimation(mOffset, mEndOffset);
anim.setAnimationListener(mOpenListener);
startAnimation(anim);

invalidate();

return true;
}

public boolean openImmediately() {
if(isOpened() || mAlwaysOpened || mMode == MODE_SLIDE) {
return false;
}

if(!isReadyForSlide()) {
mWhenReady.add(new Runnable() {

@Override
public void run() {
openImmediately();
}
});

return true;
}

mMenuView.setVisibility(View.VISIBLE);
mMode = MODE_FINISHED;
requestLayout();

if(mListener != null) {
mListener.onSlideCompleted(true);
}

return true;
}

public boolean close() {
if(!isOpened() || mAlwaysOpened || mMode == MODE_SLIDE) {
return false;
}

if(!isReadyForSlide()) {
mWhenReady.add(new Runnable() {

@Override
public void run() {
close();
}
});

return true;
}

initSlideMode();

Animation anim = new SlideAnimation(mOffset, mEndOffset);
anim.setAnimationListener(mCloseListener);
startAnimation(anim);

invalidate();

return true;
}

public boolean closeImmediately() {
if(!isOpened() || mAlwaysOpened || mMode == MODE_SLIDE) {
return false;
}

if(!isReadyForSlide()) {
mWhenReady.add(new Runnable() {

@Override
public void run() {
closeImmediately();
}
});

return true;
}

mMenuView.setVisibility(View.GONE);
mMode = MODE_READY;
requestLayout();

if(mListener != null) {
mListener.onSlideCompleted(false);
}

return true;
}

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int parentLeft = 0;
final int parentTop = 0;
final int parentRight = r - l;
final int parentBottom = b - t;

View menu = getChildAt(0);
int menuWidth = menu.getMeasuredWidth();

if(mDirection == DIRECTION_LEFT) {
menu.layout(parentLeft, parentTop, parentLeft+menuWidth, parentBottom);
} else {
menu.layout(parentRight-menuWidth, parentTop, parentRight, parentBottom);
}

if(mAlwaysOpened) {
if(mDirection == DIRECTION_LEFT) {
mOffset = menuWidth;
} else {
mOffset = 0;
}
} else if(mMode == MODE_FINISHED) {
mOffset = mDirection*menuWidth;
} else if(mMode == MODE_READY) {
mOffset = 0;
}

View main = getChildAt(1);
main.layout(
parentLeft + mOffset,
parentTop,
parentLeft + mOffset + main.getMeasuredWidth(),
parentBottom
);

invalidate();

Runnable rn;
        while((rn = mWhenReady.poll()) != null) {
        rn.run();
        }
}

private boolean isReadyForSlide() {
return (getWidth() > 0 && getHeight() > 0);
}

@Override
    protected void onMeasure(int wSp, int hSp) {
mMenuView = getChildAt(0);

        if(mAlwaysOpened) {
            View main = getChildAt(1);
            
            if(mMenuView != null && main != null) {
            measureChild(mMenuView, wSp, hSp);
                LayoutParams lp = (LayoutParams) main.getLayoutParams();
                
                if(mDirection == DIRECTION_LEFT) {
                lp.leftMargin = mMenuView.getMeasuredWidth();
                } else {
                lp.rightMargin = mMenuView.getMeasuredWidth();
                }
            }
        }
        
        super.onMeasure(wSp, hSp);
    }

private byte mFrame = 0;


@Override
protected void dispatchDraw(Canvas canvas) {
try {
if(mMode == MODE_SLIDE) {
View main = getChildAt(1);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
/*
* On new versions we redrawing main layout only
* if it's marked as dirty 
*/
if(main.isDirty()) {
mCachedCanvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
main.draw(mCachedCanvas);
}
} else {
/*
* On older versions we just redrawing our cache
* every 5th frame
*/
if(++mFrame % 5 == 0) {
mCachedCanvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
main.draw(mCachedCanvas);
}
}

/*

* Draw only visible part of menu
*/

View menu = getChildAt(0);
final int scrollX = menu.getScrollX();
final int scrollY = menu.getScrollY();

canvas.save();

if(mDirection == DIRECTION_LEFT) {
canvas.clipRect(0, 0, mOffset, menu.getHeight(), Op.REPLACE);
} else {
int menuWidth = menu.getWidth();
int menuLeft = menu.getLeft();

canvas.clipRect(menuLeft+menuWidth+mOffset, 0, menuLeft+menuWidth, menu.getHeight());
}

canvas.translate(menu.getLeft(), menu.getTop());
canvas.translate(-scrollX, -scrollY);

menu.draw(canvas);

canvas.restore();

canvas.drawBitmap(mCachedBitmap, mOffset, 0, mCachedPaint);
} else {
if(!mAlwaysOpened && mMode == MODE_READY) {
        mMenuView.setVisibility(View.GONE);
       }

super.dispatchDraw(canvas);
}
} catch(IndexOutOfBoundsException e) {
/*
* Possibility of crashes on some devices (especially on Samsung).
* Usually, when ListView is empty.
*/
}
}

private int mHistoricalX = 0;
private boolean mCloseOnRelease = false;

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if(((!mEnabled || !mInterceptTouch) && mMode == MODE_READY) || mAlwaysOpened) {
return super.dispatchTouchEvent(ev);
}

if(mMode != MODE_FINISHED) {
onTouchEvent(ev);

if(mMode != MODE_SLIDE) {
super.dispatchTouchEvent(ev);
} else {
MotionEvent cancelEvent = MotionEvent.obtain(ev);
cancelEvent.setAction(MotionEvent.ACTION_CANCEL);
super.dispatchTouchEvent(cancelEvent);
cancelEvent.recycle();
}

return true;
} else {
final int action = ev.getAction();

Rect rect = new Rect();
View menu = getChildAt(0);
menu.getHitRect(rect);

if(!rect.contains((int) ev.getX(), (int) ev.getY())) {
if (action == MotionEvent.ACTION_UP && mCloseOnRelease && !mDispatchWhenOpened) {
close();
mCloseOnRelease = false;
} else {
if(action == MotionEvent.ACTION_DOWN && !mDispatchWhenOpened) {
mCloseOnRelease = true;
}

onTouchEvent(ev);
}

if(mDispatchWhenOpened) {
super.dispatchTouchEvent(ev);
}

return true;
} else {
onTouchEvent(ev);

ev.offsetLocation(-menu.getLeft(), -menu.getTop());
menu.dispatchTouchEvent(ev);

return true;
}
}
}

private boolean handleTouchEvent(MotionEvent ev) {
if(!mEnabled) {
return false;
}

float x = ev.getX();

if(ev.getAction() == MotionEvent.ACTION_DOWN) {
mHistoricalX = (int) x;

return true;
}

if(ev.getAction() == MotionEvent.ACTION_MOVE) {

float diff = x - mHistoricalX;


if((mDirection*diff > 50 && mMode == MODE_READY) || (mDirection*diff < -50 && mMode == MODE_FINISHED)) {

mHistoricalX = (int) x;

initSlideMode();
} else if(mMode == MODE_SLIDE) {
mOffset += diff;

mHistoricalX = (int) x;

if(!isSlideAllowed()) {
finishSlide();
}
} else {
return false;
}
}

if(ev.getAction() == MotionEvent.ACTION_UP) {
if(mMode == MODE_SLIDE) {
finishSlide();
}

mCloseOnRelease = false;

return false;
}

return mMode == MODE_SLIDE;
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
boolean handled = handleTouchEvent(ev);

invalidate();

return handled;
}

private void initSlideMode() {
mCloseOnRelease = false;

View v = getChildAt(1);

if(mMode == MODE_READY) {
mStartOffset = 0;
mEndOffset = mDirection*getChildAt(0).getWidth();
} else {
mStartOffset = mDirection*getChildAt(0).getWidth();
mEndOffset = 0;
}

mOffset = mStartOffset;

if(mCachedBitmap == null || mCachedBitmap.isRecycled() || mCachedBitmap.getWidth() != v.getWidth()) {
mCachedBitmap = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);
mCachedCanvas = new Canvas(mCachedBitmap);
} else {
mCachedCanvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
}

v.setVisibility(View.VISIBLE);

mCachedCanvas.translate(-v.getScrollX(), -v.getScrollY());
v.draw(mCachedCanvas);

mMode = MODE_SLIDE;

mMenuView.setVisibility(View.VISIBLE);
}

private boolean isSlideAllowed() {
return (mDirection*mEndOffset > 0 && mDirection*mOffset < mDirection*mEndOffset && mDirection*mOffset >= mDirection*mStartOffset)
|| (mEndOffset == 0 && mDirection*mOffset > mDirection*mEndOffset && mDirection*mOffset <= mDirection*mStartOffset);
}

private void completeOpening() {
mOffset = mDirection*mMenuView.getWidth();
requestLayout();

post(new Runnable() {

@Override
public void run() {
mMode = MODE_FINISHED;
mMenuView.setVisibility(View.VISIBLE);
}
});

if(mListener != null) {
mListener.onSlideCompleted(true);
}
}

private Animation.AnimationListener mOpenListener = new Animation.AnimationListener() {

@Override
public void onAnimationStart(Animation animation) {}

@Override
public void onAnimationRepeat(Animation animation) {}

@Override
public void onAnimationEnd(Animation animation) {
completeOpening();
}
};

private void completeClosing() {
mOffset = 0;
requestLayout();

post(new Runnable() {

@Override
public void run() {
mMode = MODE_READY;
mMenuView.setVisibility(View.GONE);
}
});

if(mListener != null) {
mListener.onSlideCompleted(false);
}
}

private Animation.AnimationListener mCloseListener = new Animation.AnimationListener() {

@Override
public void onAnimationStart(Animation animation) {}

@Override
public void onAnimationRepeat(Animation animation) {}

@Override
public void onAnimationEnd(Animation animation) {
completeClosing();
}
};

private void finishSlide() {
if(mDirection*mEndOffset > 0) {
if(mDirection*mOffset > mDirection*mEndOffset/2) {
if(mDirection*mOffset > mDirection*mEndOffset) mOffset = mEndOffset;

Animation anim = new SlideAnimation(mOffset, mEndOffset);
anim.setAnimationListener(mOpenListener);
startAnimation(anim);
} else {
if(mDirection*mOffset < mDirection*mStartOffset) mOffset = mStartOffset;

Animation anim = new SlideAnimation(mOffset, mStartOffset);
anim.setAnimationListener(mCloseListener);
startAnimation(anim);
}
} else {
if(mDirection*mOffset < mDirection*mStartOffset/2) {
if(mDirection*mOffset < mDirection*mEndOffset) mOffset = mEndOffset;

Animation anim = new SlideAnimation(mOffset, mEndOffset);
anim.setAnimationListener(mCloseListener);
startAnimation(anim);
} else {
if(mDirection*mOffset > mDirection*mStartOffset) mOffset = mStartOffset;

Animation anim = new SlideAnimation(mOffset, mStartOffset);
anim.setAnimationListener(mOpenListener);
startAnimation(anim);
}
}
}

private class SlideAnimation extends Animation {

// define Speed of Slider

private static final float SPEED = 0.6f;


private float mStart;
private float mEnd;

public SlideAnimation(float fromX, float toX) {
mStart = fromX;
mEnd = toX;

setInterpolator(new DecelerateInterpolator());

float duration = Math.abs(mEnd - mStart) / SPEED;

setDuration((long) duration);
}

@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);

float offset = (mEnd - mStart) * interpolatedTime + mStart;
mOffset = (int) offset;

postInvalidate();
}

}

public static interface OnSlideListener {
public void onSlideCompleted(boolean opened);
}


}

Step 5: Run your project:





No comments :

Post a Comment

Follow me Share