MainActivity如下:
package cc.testview4; import cc.testview4.SlideView.SwitchChangedListener; import android.app.Activity; import android.os.Bundle; /** * Demo描述: * 自定义滑动控件 * * 参考资料: * http://blog.csdn.net/lfdfhl/article/details/8195441 * * 备注说明: * 在CopyOfSlideView中使用了另外一种方式: * 主要涉及到自定义控件的Touch和GestureDetector的处理 * 详细代码请参见SlideView是一种很好的方式和思路!!! * 该方式中有一点点点(很微小)BUG参见其中代码的第71行 */ public class MainActivity extends Activity { private SlideView mSlideView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); init(); } private void init(){ mSlideView=(SlideView) findViewById(R.id.slideView); mSlideView.setSwitchChangedListener(new SwitchChangedListenerImpl()); } private class SwitchChangedListenerImpl implements SwitchChangedListener{ @Override public void OnChanged(String info) { System.out.println("info="+info); } } }
SlideView如下:
package cc.testview4; import android.content.Context; import android.util.AttributeSet; import android.view.GestureDetector; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.widget.ImageView; import android.widget.RelativeLayout; public class SlideView extends RelativeLayout{ private SwitchChangedListener mSwitchChangedListener; private Context mContext; private View mSlideView; private int dotRawLeft; private int dotRawRight; private int dotRawTop; private int dotRawBottom; private int downX; private int downY; private int dotCurrentLeft; private int dotCurrentRight; private int dotCurrentTop; private int dotCurrentBottom; // 中间圆球 private ImageView mDotImageView; // 上一步 private ImageView mPreStepImageView; // 下一步 private ImageView mNextStepImageView; // 上一步箭头线 private ImageView mPreArrowImageView; // 下一步箭头线 private ImageView mNextArrowImageView; // 上一步箭头的左边相对于parent左边的位置 private int preArrowLeft; private int preArrowWidth; // 上一步箭头的右边相对于parent左边的位置 private int preArrowRight; // 下一步箭头的左边相对于parent左边的位置 private int nextArrowLeft; // 下一步箭头的右边相对于parent左边的位置 private int nextArrowWidth; private int nextArrowRight; public SlideView(Context context) { super(context); init(context); } public SlideView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } private void init(Context context){ mContext=context; LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); mSlideView = inflater.inflate(R.layout.slideview, this); mDotImageView = (ImageView) mSlideView.findViewById(R.id.dotImageView); mPreStepImageView = (ImageView) mSlideView.findViewById(R.id.preStepImageView); mNextStepImageView = (ImageView) mSlideView.findViewById(R.id.nextStepImageView); mNextArrowImageView = (ImageView) mSlideView.findViewById(R.id.nextArrowImageView); mPreArrowImageView = (ImageView) mSlideView.findViewById(R.id.preArrowImageView); this.getRawLocation(); // 自定义组件添加触摸监听事件 mDotImageView.setOnTouchListener(new TouchListenerImpl()); } //利用Post方式获取一些位置坐标 private void getRawLocation(){ mNextArrowImageView.post(new Runnable() { @Override public void run() { dotRawLeft = mDotImageView.getLeft(); dotRawRight = mDotImageView.getRight(); dotRawTop = mDotImageView.getTop(); dotRawBottom = mDotImageView.getBottom(); preArrowWidth=mPreArrowImageView.getWidth(); nextArrowWidth=mNextArrowImageView.getWidth(); } }); } private class TouchListenerImpl implements OnTouchListener{ @Override public boolean onTouch(View view, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: downX = (int) event.getRawX(); downY = (int) event.getRawY(); break; case MotionEvent.ACTION_MOVE: //手指向左滑动,dx<0 //手指向右滑动,dx>0 int distanceX =(int)event.getRawX() - downX;//移动的距离 int distanceY =(int)event.getRawY() - downY;//移动的距离 //防止越界 if (distanceX<0) { if (Math.abs(distanceX)>=preArrowWidth) { distanceX=-preArrowWidth; } } else { if (distanceX>=nextArrowWidth) { distanceX=nextArrowWidth; } } dotCurrentLeft= dotRawLeft + distanceX; dotCurrentRight = dotRawRight + distanceX; System.out.println("dotCurrentLeft="+dotCurrentLeft+",dotCurrentRight="+dotCurrentRight); if (distanceX<0&&Math.abs(distanceX)==preArrowWidth) { mSwitchChangedListener.OnChanged("上一步"); } if (distanceX>0&&distanceX==nextArrowWidth) { mSwitchChangedListener.OnChanged("下一步"); } mDotImageView.layout(dotCurrentLeft, dotRawTop, dotCurrentRight,dotRawBottom); break; case MotionEvent.ACTION_UP: mDotImageView.layout(dotRawLeft, dotRawTop, dotRawRight,dotRawBottom); break; default: break; } return true; } } // 回调接口 public interface SwitchChangedListener { public void OnChanged(String info); } public void setSwitchChangedListener(SwitchChangedListener switchChangedListener) { this.mSwitchChangedListener=switchChangedListener; } }
CopyOfSlideView如下:
package cc.testview4; import android.content.Context; import android.util.AttributeSet; import android.view.GestureDetector; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.Toast; public class CopyOfSlideView extends RelativeLayout{ private SwitchChangedListener mSwitchChangedListener; private Context mContext; private View mSlideView; private int dotRawLeft; private int dotRawRight; private int dotRawTop; private int dotRawBottom; // 中间圆球 private ImageView mDotImageView; // 上一步 private ImageView mPreStepImageView; // 下一步 private ImageView mNextStepImageView; // 上一步箭头线 private ImageView mPreArrowImageView; // 下一步箭头线 private ImageView mNextArrowImageView; // 上一步箭头的左边相对于parent左边的位置 private int preArrowLeft; // 上一步箭头的右边相对于parent左边的位置 private int preArrowRight; // 下一步箭头的左边相对于parent左边的位置 private int nextArrowLeft; // 下一步箭头的右边相对于parent左边的位置 private int nextArrowRight; // 在X轴上一共移动的距离 private int sliddingSumX = 0; private RelativeLayout mSlideViewRelativeLayout; private GestureDetector mGestureDetector; private SlideViewGestureListener mSlideViewGestureListener; public CopyOfSlideView(Context context) { super(context); init(context); } public CopyOfSlideView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } private void init(Context context){ mContext=context; LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); mSlideView = inflater.inflate(R.layout.slideview, this); mDotImageView = (ImageView) mSlideView.findViewById(R.id.dotImageView); mPreStepImageView = (ImageView) mSlideView.findViewById(R.id.preStepImageView); mNextStepImageView = (ImageView) mSlideView.findViewById(R.id.nextStepImageView); mNextArrowImageView = (ImageView) mSlideView.findViewById(R.id.nextArrowImageView); mPreArrowImageView = (ImageView) mSlideView.findViewById(R.id.preArrowImageView); mSlideViewRelativeLayout = (RelativeLayout) findViewById(R.id.slideView_RelativeLayout); this.getRawLocation(); mSlideViewGestureListener = new SlideViewGestureListener(); mGestureDetector = new GestureDetector(mContext,mSlideViewGestureListener); // 自定义组件添加触摸监听事件 // 利用以下一句是对整个自定义控件实现了Touch监听,滑块滑动时正常 mSlideView.setOnTouchListener(new TouchListenerImpl()); // 利用以下一句是对滑块实现了Touch监听,滑块滑动时有抖动现象,原因不明待查 //mDotImageView.setOnTouchListener(new TouchListenerImpl()); } //利用Post方式获取一些位置坐标 private void getRawLocation(){ mNextArrowImageView.post(new Runnable() { @Override public void run() { dotRawLeft = mDotImageView.getLeft(); dotRawRight = mDotImageView.getRight(); dotRawTop = mDotImageView.getTop(); dotRawBottom = mDotImageView.getBottom(); preArrowLeft = mPreArrowImageView.getLeft(); preArrowRight = mPreArrowImageView.getRight(); nextArrowLeft = mNextArrowImageView.getLeft(); nextArrowRight = mNextArrowImageView.getRight(); } }); } private class TouchListenerImpl implements OnTouchListener{ @Override public boolean onTouch(View view, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_UP: // 滑动距离小于五分之四,回到原位 if (Math.abs(sliddingSumX) < (preArrowRight - preArrowLeft) * 4 / 5) { mDotImageView.layout(dotRawLeft, dotRawTop, dotRawRight,dotRawBottom); sliddingSumX = 0; } else { if (mDotImageView.getLeft() < dotRawLeft) { Toast.makeText(mContext, "上一步", 0).show(); mSwitchChangedListener.OnChanged("到达了上一步"); mDotImageView.layout(dotRawLeft, dotRawTop,dotRawRight, dotRawBottom); sliddingSumX = 0; } else { Toast.makeText(mContext, "下一步", 0).show(); mSwitchChangedListener.OnChanged("到达了下一步"); mDotImageView.layout(dotRawLeft, dotRawTop,dotRawRight, dotRawBottom); sliddingSumX = 0; } } break; default: break; } /** * 注意: * 在OnTouchListener中把move和down事件处理都转交给了mGestureDetector. * 在OnTouchListener中只处理了up事件---在手指抬起后显示dotImageView. */ return mGestureDetector.onTouchEvent(event); } } // 自定义控件的手势 // 注意:在相应的方法中返回true,表示已经消费完事件 private class SlideViewGestureListener implements GestureDetector.OnGestureListener { @Override public boolean onDown(MotionEvent e) { return true; } // 在自定义控件滑动时候执行此方法 @Override public boolean onScroll(MotionEvent e1, MotionEvent e2,float distanceX, float distanceY) { sliddingSumX = sliddingSumX + (int) distanceX; // 再次显示dotImageView时只需要改变X轴方向的值 // 往左拉动,X增大;往右拉动,x减小 // 注意:往右拉动,distanceX为负值;往左拉动,distanceX为正值. // 所以不是:rawLeft+sumX, rawTop, rawRight+sumX, rawBottom // 而应该是:rawLeft-sumX, rawTop, rawRight-sumX, rawBottom if (dotRawLeft - sliddingSumX >= (preArrowLeft - (mDotImageView.getWidth() * 0.5))&& dotRawRight - sliddingSumX <= nextArrowRight+ ((mDotImageView.getWidth() * 0.5))) { System.out.println("==> distanceX="+distanceX+",sliddingSumX="+sliddingSumX); mDotImageView.layout (dotRawLeft - sliddingSumX, dotRawTop,dotRawRight - sliddingSumX, dotRawBottom); } else { System.out.println("超过了两头的边界"); } return true; } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,float velocityY) { return false; } @Override public void onLongPress(MotionEvent e) { } @Override public void onShowPress(MotionEvent e) { } @Override public boolean onSingleTapUp(MotionEvent e) { return false; } } // 回调接口 public interface SwitchChangedListener { public void OnChanged(String info); } public void setSwitchChangedListener(SwitchChangedListener switchChangedListener) { this.mSwitchChangedListener=switchChangedListener; } }
main.xml如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <cc.testview4.SlideView android:id="@+id/slideView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" /> </RelativeLayout>
slideview.xml如下:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/slideView_RelativeLayout" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:background="@drawable/step_bg" android:orientation="horizontal" > <ImageView android:id="@+id/dotImageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:background="@drawable/step_ball" android:clickable="false" /> <ImageView android:id="@+id/preArrowImageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:layout_toLeftOf="@id/dotImageView" android:background="@drawable/step_preline" /> <ImageView android:id="@+id/preStepImageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:layout_marginRight="10dip" android:layout_toLeftOf="@id/preArrowImageView" android:background="@drawable/step_pre" /> <ImageView android:id="@+id/nextArrowImageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:layout_toRightOf="@id/dotImageView" android:background="@drawable/step_nextline" /> <ImageView android:id="@+id/nextStepImageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:layout_marginLeft="10dip" android:layout_toRightOf="@id/nextArrowImageView" android:background="@drawable/step_next" /> </RelativeLayout>