MainActivity:
package com.example.test; import java.util.ArrayList; import java.util.List; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.view.Window; import android.widget.ArrayAdapter; import android.widget.ListView; public class MainActivity extends ActionBarActivity { private SlidingLayout slidingLayout = null; private ListView leftList = null; private ListView rightList = null; private List<String> leftData = null; private List<String> rightData = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); initViews(); initData(); } /** * 初始化控件 */ protected void initViews() { slidingLayout = (SlidingLayout) findViewById(R.id.sliding_layout); leftList = (ListView) findViewById(R.id.left_list); rightList = (ListView) findViewById(R.id.right_list); slidingLayout.setScrollEvent(rightList, findViewById(R.id.vertical_right_shadow)); slidingLayout.setLeftView(leftList, findViewById(R.id.left_top_view)); } /** * 初始化数据 */ protected void initData() { leftData = new ArrayList<String>(); leftData.add("left data 1"); leftData.add("left data 2"); leftData.add("left data 3"); leftData.add("left data 4"); rightData = new ArrayList<String>(); rightData.add("right data 1"); rightData.add("right data 2"); rightData.add("right data 3"); rightData.add("right data 4"); ArrayAdapter<String> leftAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1, leftData); ArrayAdapter<String> rightAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1, rightData); leftList.setAdapter(leftAdapter); rightList.setAdapter(rightAdapter); } }侧滑的slidingLayout是集成于LinearLayout,目前只允许有两个child,然后在slidingLayout分别对两个child(左侧布局和右侧布局)进行移动,以及阴影等效果的添加
SlidingLayout:
package com.example.test; import android.content.Context; import android.graphics.Color; import android.os.AsyncTask; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import android.view.View.OnTouchListener; import android.view.ViewConfiguration; import android.widget.LinearLayout; public class SlidingLayout extends LinearLayout implements OnTouchListener { /** * 滚动显示和隐藏左侧布局时,手指滑动需要达到的速度 */ public static final int SNAP_VELOCITY = 200; /** * 屏幕宽度值�? */ private int screenWidth; /** * 在被判定为滚动之前用户手指可以移动的�?��值�? */ private int touchSlop; /** * 记录手指按下时的横坐标�? */ private float xDown; /** * 记录手指按下时的纵坐标�? */ private float yDown; /** * 记录手指移动时的横坐标�? */ private float xMove; /** * 记录手指移动时的纵坐标�? */ private float yMove; /** * 记录手机抬起时的横坐标�? */ private float xUp; /** * 左侧布局当前是显示还是隐藏�?只有完全显示或隐藏时才会更改此�?,滑动过程中此�?无效�? */ private boolean isLeftLayoutVisible; /** * 是否正在滑动�? */ private boolean isSliding; /** * 左侧布局对象�? */ private View leftLayout; /** * 右侧布局对象�? */ private View rightLayout; /** * 用于监听侧滑事件的View�? */ private View mBindView; /** * 左侧布局的参数,通过此参数来重新确定左侧布局的宽度,以及更改leftMargin的�?�? */ private MarginLayoutParams leftLayoutParams; /** * 右侧布局的参数,通过此参数来重新确定右侧布局的宽度�? */ private MarginLayoutParams rightLayoutParams; private MarginLayoutParams shadowLayoutParams; /** * 用于计算手指滑动的�?度�? */ private VelocityTracker mVelocityTracker; private int fixWidth; private int contentWidth; private boolean isOpen = false; private View fixView;// 固定的view; private View topView; private View shadowView; private boolean flag = false;// /** * 重写SlidingLayout的构造函数,其中获取了屏幕的宽度�? * * @param context * @param attrs */ public SlidingLayout(Context context, AttributeSet attrs) { super(context, attrs); fixWidth = SystemUtil.dipToPx(context,52); screenWidth = SystemUtil.getScreenWidth(context); touchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); contentWidth = screenWidth - fixWidth; } /** * 绑定监听侧滑事件的View,即在绑定的View进行滑动才可以显示和隐藏左侧布局 * * @param bindView */ public void setScrollEvent(View bindView ,View shadowView) { mBindView = bindView; this.shadowView = shadowView; mBindView.setOnTouchListener(this); } /** * 设置left view * @param view * @param topView */ public void setLeftView(View view, View topView) { fixView = view; fixView.setOnTouchListener(this); //设置透明度 this.topView = topView; if (topView.getBackground() == null) { topView.setBackgroundColor(Color.WHITE);; topView.getBackground().setAlpha(0); } } /** * 将屏幕滚动到左侧布局界面,滚动速度设定为30. */ public void scrollToLeftLayout() { new ScrollTask().execute(30); } /** * 将屏幕滚动到右侧布局界面,滚动速度设定为-30. */ public void scrollToRightLayout() { new ScrollTask().execute(-30); } /** * 左侧布局是否显示出来 */ public boolean isLeftLayoutVisible() { return isLeftLayoutVisible; } /** * 在onLayout中重新设定左侧布�?��右侧布局的参数�? */ @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); if (changed) { // 获取左侧布局对象 leftLayout = getChildAt(0); leftLayoutParams = (MarginLayoutParams) leftLayout .getLayoutParams(); leftLayoutParams.width = contentWidth; leftLayout.setLayoutParams(leftLayoutParams); // 获取右侧布局对象 rightLayout = getChildAt(1); rightLayoutParams = (MarginLayoutParams) rightLayout .getLayoutParams(); rightLayoutParams.width = contentWidth; rightLayout.setLayoutParams(rightLayoutParams); shadowLayoutParams = (MarginLayoutParams) shadowView.getLayoutParams(); } } @Override public boolean onTouch(View v, MotionEvent event) { if (v.getId() == R.id.left_list) { if (isOpen) { if(event.getRawX() >= fixWidth && !flag) { xDown = event.getRawX(); yDown = event.getRawY(); flag = true; } else if(event.getRawX() < fixWidth) { flag = false; return true; } } else { return false; } } createVelocityTracker(event); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: // 手指按下时,记录按下时的横坐�? xDown = event.getRawX(); yDown = event.getRawY(); break; case MotionEvent.ACTION_MOVE: // 手指移动时,对比按下时的横坐标,计算出移动的距离,来调整右侧布局的leftMargin值,从�?显示和隐藏左侧布�? xMove = event.getRawX(); yMove = event.getRawY(); int moveDistanceX = (int) (xMove - xDown); float alpha = 0; int distanceY = (int) (yMove - yDown); if (moveDistanceX <= 0 && (-moveDistanceX > touchSlop || isSliding)) { if (!isOpen) { isSliding = true; rightLayoutParams.leftMargin = moveDistanceX; if (rightLayoutParams.leftMargin < -(contentWidth - fixWidth)) { rightLayoutParams.leftMargin = -(contentWidth - fixWidth); } } else { rightLayoutParams.leftMargin = -(contentWidth - fixWidth); } rightLayout.setLayoutParams(rightLayoutParams); shadowLayoutParams.rightMargin = -rightLayoutParams.leftMargin; shadowView.setLayoutParams(shadowLayoutParams); } if (moveDistanceX >= 0 && (moveDistanceX > touchSlop || isSliding)) { if ((isSliding || Math.abs(distanceY) <= touchSlop) && isOpen) { isSliding = true; rightLayoutParams.leftMargin = moveDistanceX - (contentWidth - fixWidth); if (rightLayoutParams.leftMargin > 0) { rightLayoutParams.leftMargin = 0; } } else if((isSliding || Math.abs(distanceY) <= touchSlop)){ rightLayoutParams.leftMargin = 0; } rightLayout.setLayoutParams(rightLayoutParams); shadowLayoutParams.rightMargin = -rightLayoutParams.leftMargin; shadowView.setLayoutParams(shadowLayoutParams); } alpha = Math.abs(rightLayoutParams.leftMargin) / (float) (1.5 * (contentWidth - fixWidth)); if (topView.getBackground() != null) { topView.getBackground().setAlpha((int) (alpha * 255)); topView.invalidate(); } break; case MotionEvent.ACTION_UP: xUp = event.getRawX(); int upDistanceX = (int) (xUp - xDown); if (isSliding) { // 手指抬起时,进行判断当前手势的意图,从�?决定是滚动到左侧布局,还是滚动到右侧布局 if (wantToShowLeftLayout()) { if (shouldScrollToLeftLayout()) { scrollToLeftLayout(); } else { scrollToRightLayout(); } } else if (wantToShowRightLayout()) { if (shouldScrollToRightLayout()) { scrollToRightLayout(); } else { scrollToLeftLayout(); } } } else if (Math.abs(upDistanceX) < touchSlop && !isOpen) { //点击效果 scrollToRightLayout(); } recycleVelocityTracker(); break; } if(v.getId() == R.id.left_list) { if(isOpen) { return true; } } if (v.isEnabled()) { if (isSliding) { unFocusBindView(); unFocusLeftView(); return true; } if (isOpen) { return false; } } return true; } /** * 判断当前手势的意图是不是想显示右侧布�??如果手指移动的距离是负数,且当前左侧布局是可见的,则认为当前手势是想要显示右侧布�?? * * @return 当前手势想显示右侧布�?��回true,否则返回false�? */ private boolean wantToShowRightLayout() { return xUp - xDown < 0 && !isOpen; } /** * 判断当前手势的意图是不是想显示左侧布�??如果手指移动的距离是正数,且当前左侧布局是不可见的,则认为当前手势是想要显示左侧布局�? * * @return 当前手势想显示左侧布�?��回true,否则返回false�? */ private boolean wantToShowLeftLayout() { return xUp - xDown > 0 && isOpen; } /** * 判断是否应该滚动将左侧布�?��示出来�?如果手指移动距离大于屏幕�?/2,或者手指移动�?度大于SNAP_VELOCITY�? * 就认为应该滚动将左侧布局展示出来�? * * @return 如果应该滚动将左侧布�?��示出来返回true,否则返回false�? */ private boolean shouldScrollToLeftLayout() { return xUp - xDown > (contentWidth - fixWidth) / 2 || getScrollVelocity() > SNAP_VELOCITY; } /** * 判断是否应该滚动将右侧布�?��示出来�?如果手指移动距离加上leftLayoutPadding大于屏幕�?/2�? * 或�?手指移动速度大于SNAP_VELOCITY�?就认为应该滚动将右侧布局展示出来�? * * @return 如果应该滚动将右侧布�?��示出来返回true,否则返回false�? */ private boolean shouldScrollToRightLayout() { return xDown - xUp > (contentWidth - fixWidth) / 2 || getScrollVelocity() > SNAP_VELOCITY; } /** * 创建VelocityTracker对象,并将触摸事件加入到VelocityTracker当中�? * * @param event * 右侧布局监听控件的滑动事�? */ private void createVelocityTracker(MotionEvent event) { if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } mVelocityTracker.addMovement(event); } /** * 获取手指在右侧布局的监听View上的滑动速度。 * * @return 滑动速度,以每秒钟移动了多少像素值为单位。 */ private int getScrollVelocity() { mVelocityTracker.computeCurrentVelocity(1000); int velocity = (int) mVelocityTracker.getXVelocity(); return Math.abs(velocity); } /** * 回收VelocityTracker对象�? */ private void recycleVelocityTracker() { mVelocityTracker.recycle(); mVelocityTracker = null; } /** * 使用可以获得焦点的控件在滑动的时候失去焦点�? */ private void unFocusBindView() { if (mBindView != null) { mBindView.setPressed(false); mBindView.setFocusable(false); mBindView.setFocusableInTouchMode(false); } } private void unFocusLeftView() { if (fixView != null) { fixView.setPressed(false); fixView.setFocusable(false); fixView.setFocusableInTouchMode(false); } } class ScrollTask extends AsyncTask<Integer, Integer, Integer> { @Override protected Integer doInBackground(Integer... speed) { int leftMargin = rightLayoutParams.leftMargin; // 根据传入的�?度来滚动界面,当滚动到达左边界或右边界时,跳出循环�? while (true) { leftMargin = leftMargin + speed[0]; if (leftMargin < -(contentWidth - fixWidth)) { leftMargin = -(contentWidth - fixWidth); publishProgress(leftMargin); break; } if (leftMargin > 0) { leftMargin = 0; publishProgress(leftMargin); break; } publishProgress(leftMargin); // 为了要有滚动效果产生,每次循环使线程睡眠20毫秒,这样肉眼才能够看到滚动动画�? sleep(15); } if (speed[0] > 0) { isLeftLayoutVisible = false; isOpen = false; } else { isLeftLayoutVisible = true; isOpen = true; } isSliding = false; return leftMargin; } @Override protected void onProgressUpdate(Integer... leftMargin) { rightLayoutParams.leftMargin = leftMargin[0]; rightLayout.setLayoutParams(rightLayoutParams); shadowLayoutParams.rightMargin = Math.abs(rightLayoutParams.leftMargin); shadowView.setLayoutParams(shadowLayoutParams); float alpha = Math.abs(rightLayoutParams.leftMargin) / (float) (1.5 * (contentWidth - fixWidth)); if (topView.getBackground() != null) { topView.getBackground().setAlpha((int) (alpha * 255)); topView.invalidate(); } unFocusBindView(); } @Override protected void onPostExecute(Integer leftMargin) { rightLayoutParams.leftMargin = leftMargin; rightLayout.setLayoutParams(rightLayoutParams); shadowLayoutParams.rightMargin = Math.abs(rightLayoutParams.leftMargin); shadowView.setLayoutParams(shadowLayoutParams); } } /** * 重新再次设置布局 */ public void resetLayoutParams() { //�?��在重新设置下,在contactDetailActivity中添加笔记后才能自动刷新,不知道为什么??? rightLayout.setLayoutParams(rightLayoutParams); shadowLayoutParams.rightMargin = -rightLayoutParams.leftMargin; shadowView.setLayoutParams(shadowLayoutParams); } /** * 使当前线程睡眠指定的毫秒数�? * * @param millis * 指定当前线程睡眠多久,以毫秒为单�? */ private void sleep(long millis) { try { Thread.sleep(millis); } catch (InterruptedException e) { e.printStackTrace(); } } }这个其实是借鉴大神做的修改,详细地址:http://blog.csdn.net/guolin_blog/article/details/8744400
最后的activity_main.xml文件
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.test.MainActivity" > <com.example.test.SlidingLayout android:id="@+id/sliding_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <RelativeLayout android:id="@+id/left_layout" android:layout_width="match_parent" android:layout_height="match_parent" > <ListView android:id="@+id/left_list" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#ffffffff" android:cacheColorHint="@null" > </ListView> <ImageView android:id="@+id/left_top_view" android:layout_width="match_parent" android:layout_height="match_parent" /> <ImageView android:id="@+id/vertical_right_shadow" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_alignParentRight="true" android:background="@drawable/sliding_vertcal_shadow" /> </RelativeLayout> <RelativeLayout android:id="@+id/right_layout" android:layout_width="match_parent" android:layout_height="match_parent" > <ListView android:id="@+id/right_list" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#ffffffff" android:cacheColorHint="@null" > </ListView> </RelativeLayout> </com.example.test.SlidingLayout> </FrameLayout>
点击下载