Android自定义View示例(三)—滑动控件

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>
时间: 2024-09-28 05:01:15

Android自定义View示例(三)—滑动控件的相关文章

Android自定义View圆形进度条控件(三)

继续练习自定义View,这次带来的圆形进度条控件与之前的圆形百分比控件大同小异,这次涉及到了渐变渲染以及画布旋转等知识点,效果如下: 虽然步骤类似,但是我还是要写,毕竟基础的东西就是要多练 1.在res/values文件夹下新建attrs.xml文件,编写自定义属性: <?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="Circ

Android自定义View简易折线图控件(二)

继续练习自定义View,这次带来的是简易折线图,支持坐标点点击监听,效果如下: 画坐标轴.画刻度.画点.连线..x.y轴的数据范围是写死的 1 <= x <= 7 ,1 <= y <= 70 ..写活的话涉及到坐标轴刻度的动态计算.坐标点的坐标修改,想想就头大,这里只练习自定义View. 1.在res/values文件夹下新建attrs.xml文件,编写自定义属性: <?xml version="1.0" encoding="utf-8"

android自定义按钮示例(重写imagebutton控件实现图片按钮)_Android

由于项目这种类型的图片按钮比较多,所以重写了ImageButton类. 复制代码 代码如下: package me.henji.widget; import android.content.Context;import android.graphics.ColorMatrix;import android.graphics.ColorMatrixColorFilter;import android.util.AttributeSet;import android.view.MotionEvent

android自定义按钮示例(重写imagebutton控件实现图片按钮)

由于项目这种类型的图片按钮比较多,所以重写了ImageButton类. 复制代码 代码如下:package me.henji.widget; import android.content.Context;import android.graphics.ColorMatrix;import android.graphics.ColorMatrixColorFilter;import android.util.AttributeSet;import android.view.MotionEvent;

android自定义view-Android在自定义View控制Activity里控件

问题描述 Android在自定义View控制Activity里控件 最近在学习Android,想做一个效果遇到了困难.我自定义了一个View,然后在View里设置触摸事件,点击一个出现一个按钮, 再点击一下按钮消失.我不知道怎么在自定义View里添加Button,就放在了布局了.但是用在自定义View设置的点击事件来控 制布局里的按钮?跪谢跪谢. 解决方案 以下是在Activity里的操作 private Button bt1;//你的按钮控件 View myView=View.inflate(

Android自定义View实现等级滑动条的实例

Android自定义View实现等级滑动条的实例 实现效果图: 思路: 首先绘制直线,然后等分直线绘制点: 绘制点的时候把X值存到集合中. 然后绘制背景图片,以及图片上的数字. 点击事件down的时候,换小图片为大图片.move的时候跟随手指移动. up的时候根据此时的X计算最近的集合中的点,然后自动吸附回去. 1,自定义属性 <?xml version="1.0" encoding="utf-8"?> <resources> <dec

Android自定义View的三个构造函数

自定义View有三个构造方法,它们的作用是不同的. public MyView(Context context) { super(context); } public MyView(Context context, AttributeSet attrs) { super(context, attrs); } public MyView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, de

Android重写View实现全新的控件_Android

通常情况下,Android实现自定义控件无非三种方式. Ⅰ.继承现有控件,对其控件的功能进行拓展. Ⅱ.将现有控件进行组合,实现功能更加强大控件. Ⅲ.重写View实现全新的控件 本文来讨论最难的一种自定义控件形式,重写View来实现全新的控件. 首先,我们要明白在什么样的情况下,需要重写View来实现一种全新的控件,一般当我们遇到了原生控件无法满足我们现有的需求的时候,我们此时就可以考虑创建一个全新的View来实现我们所需要的功能.创建一个全新View实现自定义控件,无非分成这么几步: Ⅰ.在

Android重写View实现全新的控件

通常情况下,Android实现自定义控件无非三种方式. Ⅰ.继承现有控件,对其控件的功能进行拓展. Ⅱ.将现有控件进行组合,实现功能更加强大控件. Ⅲ.重写View实现全新的控件 本文来讨论最难的一种自定义控件形式,重写View来实现全新的控件. 首先,我们要明白在什么样的情况下,需要重写View来实现一种全新的控件,一般当我们遇到了原生控件无法满足我们现有的需求的时候,我们此时就可以考虑创建一个全新的View来实现我们所需要的功能.创建一个全新View实现自定义控件,无非分成这么几步: Ⅰ.在