Android自定义View实现拖动选择按钮

本文为大家分享了Android实现拖动选择按钮的具体代码,供大家参考,具体内容如下

效果图

View代码

第一步:自定义属性

 <declare-styleable name="DragView">
  <attr name="icon_drag" format="reference"/>
  <attr name="color_circle" format="color"/>
  <attr name="dot_num" format="integer"/>
 </declare-styleable>

第二步:自定义圆形

public class CircleView extends View {
 /**
  * 默认颜色
  */
 private final int DEFAULT_COLOR = Color.LTGRAY;
 /**
  * 默认半径dp
  */
 private final float DEFAULT_RADIUS = 32;
 private int mColor;
 private Paint mCirclePaint;
 private float mRadius;
 private float mCenterX;
 private float mCenterY;

 public CircleView(Context context)
 {
  this(context, null);
 }

 public CircleView(Context context, AttributeSet attrs)
 {
  this(context, attrs, 0);
 }

 public CircleView(Context context, AttributeSet attrs, int defStyleAttr)
 {
  super(context, attrs, defStyleAttr);
  TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.DragView);
  mColor = array.getColor(R.styleable.DragView_color_circle,DEFAULT_COLOR);
  mCirclePaint = new Paint();
  mCirclePaint.setColor(mColor);

  mCenterY = mCenterX = mRadius = getMeasuredWidth() == 0?DEFAULT_RADIUS:getMeasuredWidth()/2;
  array.recycle();
 }

 public float getRadius(){
  return mRadius;
 }

 public int getColor()
 {
  return mColor;
 }

 @Override
 protected void onDraw(Canvas canvas)
 {
  canvas.drawCircle(mCenterX,mCenterY,mRadius,mCirclePaint);
 }
}

第三步:自定义拖动按钮

public class DragView extends RelativeLayout implements View.OnTouchListener {

 private Drawable mDragIcon;//拖动图标
 private ImageView mDragView;//拖动图标ImageView
 private int mCircleColor;//圆的颜色
 private Context mContext;//上下文
 private int mDotNum;//节点数量

 private int mWidth;//组件的宽度
 private int mHight;//组件的高度
 private int mCircleRadius;//园的半径
 private int mDragWidth;//拖动图标的宽度
 private int mLineWidth,mLineHeight;//中间线的长宽

 private float mStartX;//开始拖动的屏幕坐标
 private float mCurX;//开始拖动的触点坐标
 private float mMinX;//拖动范围的最小值
 private float mMaxX;//拖动范围的最大值

 private OnNodeSelect mOnNodeSelect;//回调接口

 public DragView(Context context) {
  this(context,null);
 }

 public DragView(Context context, AttributeSet attrs) {
  this(context, attrs,0);
 }

 public DragView(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
  TypedArray array=context.obtainStyledAttributes(attrs, R.styleable.DragView);
  mDragIcon=array.getDrawable(R.styleable.DragView_icon_drag);
  mCircleColor=array.getColor(R.styleable.DragView_color_circle,Color.WHITE);
  mDotNum=array.getInt(R.styleable.DragView_dot_num,2);
  array.recycle();
  mContext=context;
  initView();
 }

 /**
  *视图初始化,这个方法的作用是把所有的视图添加进来,并做一些初始化的配置
  * 其实可以用LayoutInflater把xml的布局文件加载进来,这样比较简便
  */
 public void initView(){
  for (int i=0;i<mDotNum;i++){
   CircleView circleView=new CircleView(mContext);
   circleView.setOnTouchListener(this);
   addView(circleView);
  }

  View view=new View(mContext);
  view.setBackgroundColor(mCircleColor);
  addView(view);

  // TODO: 2016/4/21 top not right
  mDragView=new ImageView(mContext);
  mDragView.setImageDrawable(mDragIcon);
  mDragView.setOnTouchListener(this);
  addView(mDragView);
 }

 /**
  *这一步主要是为了测量、配置每个view的大小,以便于后面触摸事件的处理
  */
 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  super.onMeasure(widthMeasureSpec, heightMeasureSpec);

  mWidth=getMeasuredWidth();
  mHight=getMeasuredHeight();

  mCircleRadius=dp2px(mContext,32);
  mDragWidth=dp2px(mContext,50);
  mLineWidth=mWidth-mDragWidth;
  mLineHeight=mCircleRadius/2;

  int count=getChildCount();
  for (int i=0;i<count;i++){
   View view=getChildAt(i);
   LinearLayout.LayoutParams params;
   if (view instanceof CircleView){
    params=new LinearLayout.LayoutParams(mCircleRadius,mCircleRadius);
    view.setLayoutParams(params);
   }else if (view instanceof ImageView){
    params=new LinearLayout.LayoutParams(mDragWidth,mDragWidth);
    view.setLayoutParams(params);
   }else {
    params=new LinearLayout.LayoutParams(mLineWidth,mLineHeight);
    view.setLayoutParams(params);
   }
  }

 }

 /**
  *这一步主要是为了放置每个view的位置,如果用LayoutInflater加载布局文件,那这一步就可以省略了
  */
 @Override
 protected void onLayout(boolean changed, int l, int t, int r, int b) {
//  super.onLayout(changed, l, t, r, b);
  if (changed){
   int count =getChildCount();

   int dLeft=0;
   int dTop=mHight/2-mDragWidth/2;

   int cLeft=mDragWidth/2-mCircleRadius/2;
   int cTop=dTop+mDragWidth/2-mCircleRadius/2;

   int lLeft=mDragWidth/2;
   int lTop=dTop+mDragWidth/2-mLineHeight/2;

   mMinX=dLeft;
   mMaxX=dLeft+mLineWidth;

   int cIndex=0;
   int cSpace=0;

   for (int i=0;i<count;i++){
    View view=getChildAt(i);
    if (view instanceof CircleView){
     cLeft=cLeft+cSpace;
     view.layout(cLeft,cTop,cLeft+mCircleRadius,cTop+mCircleRadius);
     cIndex++;
     cSpace=cIndex*mLineWidth;
    }else if (view instanceof ImageView){
     view.layout(dLeft,dTop,dLeft+mDragWidth,dTop+mDragWidth);
    }else {
     view.layout(lLeft,lTop,lLeft+mLineWidth,lTop+mLineHeight);
    }
   }
  }
 }

 /**
  *触碰事件的处理,这是自定义view比较重要的地方
  */
 @Override
 public boolean onTouch(View v, MotionEvent event) {
  if (v instanceof ImageView){
   switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:

     mStartX = (int) event.getRawX();
     mCurX = v.getTranslationX();//获取view的偏移量
     v.setPressed(true);
     break;

    case MotionEvent.ACTION_MOVE:
     float x = mCurX + event.getRawX() - mStartX;
     if (x >= 0 && x <= mMaxX - mMinX) {
      v.setTranslationX(mCurX + event.getRawX() - mStartX);
     }

     break;

    case MotionEvent.ACTION_UP:
    case MotionEvent.ACTION_CANCEL:

     int distance=(int) (event.getRawX()-mStartX);
     if (distance>0){
      if (Math.abs(distance)>mLineWidth/2){
       v.setTranslationX(mCurX + event.getRawX() - mStartX);
       setAnim(mLineWidth,1);
      }else {
       v.setTranslationX(mCurX + event.getRawX() - mStartX);
       setAnim(0,0);
      }
     }else if (distance<0){
      if (Math.abs(distance)>mLineWidth/2){
       v.setTranslationX(mCurX + event.getRawX() - mStartX);
       setAnim(0,0);
      }else {
       v.setTranslationX(mCurX + event.getRawX() - mStartX);
       setAnim(mLineWidth,1);
      }
     }

     break;
   }
  }else if (v instanceof CircleView){
   switch (event.getAction()) {
    case MotionEvent.ACTION_UP:
     if (event.getRawX()>getDisplayWidth()/2){
      setAnim(mLineWidth,1);
     }else {
      setAnim(0,0);
     }
     break;
   }
  }
  return true;
 }

 //设置平移动画
 private void setAnim(float moveX, final int scrollPosition) {
  ObjectAnimator animator = ObjectAnimator.ofFloat(mDragView, "translationX", mDragView.getTranslationX(), moveX);
  animator.setDuration(300);
  animator.start();
  if (mOnNodeSelect != null) {
   mOnNodeSelect.onNodeSelect(scrollPosition);
  }
 }

 public void setNodeSelectListener(OnNodeSelect onNodeSelect) {
  mOnNodeSelect = onNodeSelect;
 }

 //事件回调接口
 public interface OnNodeSelect {
  void onNodeSelect(int position);
 }

 //dp转px
 public int dp2px(Context context, float dpValue)
 {
  final float scale = context.getResources().getDisplayMetrics().density;
  return (int) (dpValue * scale + 0.5f);
 }

 //获取屏幕宽度
 public int getDisplayWidth(){
  DisplayMetrics metrics=new DisplayMetrics();
  ((Activity)mContext).getWindowManager().getDefaultDisplay().getMetrics(metrics);
  return metrics.widthPixels;
 }
}

使用方法

布局文件:

 <com.pengkv.apple.weight.DragView
  android:id="@+id/view_drag"
  android:layout_width="200dp"
  app:icon_drag="@drawable/ic_drag"
  app:color_circle="#CCCCCC"
  app:dot_num="2"
  android:layout_height="60dp"/>

页面代码:

 dragView=(DragView)view.findViewById(R.id.view_drag);
 dragView.setNodeSelectListener(new DragView.OnNodeSelect() {
  @Override
  public void onNodeSelect(int position) {
   Toast.makeText(getActivity(),"我选择了"+position,Toast.LENGTH_SHORT).show();
  }
 });

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android自定义View制作仪表盘界面

    前言 最近我跟自定义View杠上了,甚至说有点上瘾到走火入魔了.身为菜鸟的我自然要查阅大量的资料,学习大神们的代码,这不,前两天正好在郭神在微信公众号里推送一片自定义控件的文章--一步步实现精美的钟表界面.正适合我这种菜鸟来学习,闲着没事,我就差不多依葫芦画瓢也写了一个自定义表盘View,现在纯粹最为笔记记录下来.先展示下效果图: 下面进入正题 自定义表盘属性 老规矩,先在attrs文件里添加表盘自定义属性 <declare-styleable name="WatchView"&

  • Android自定义View圆形和拖动圆、跟随手指拖动效果

    单纯的自定义一个圆非常简单 只需要几步就完成 拖动圆添加实现触摸事件即可 我在第一次自定义View圆遇到的几个Bug: 1.拖动圆的话在xml里面设置的自定义圆的宽和高是它能活动的空间的大小 不是圆控件的大小 如果你定义了100dp 拖动它的时候超过100dp这个距离这个圆就会看不见 就像下面这样 如果想活动于整个屏幕直接给宽和高match_parent属性就好了 2.我在定义充满属性match_parent的时候运行会报错,什么方法都用了就是不行,耐心等待过一会就好了-有可能是studio没来

  • Android自定义View之自定义评价打分控件RatingBar实现自定义星星大小和间距

    在Android开发中,我们经常会用到对商家或者商品的评价,运用星星进行打分.然而在Android系统中自带的打分控件,RatingBar特别不好用,间距和大小无法改变.所以,我就自定义了一个特别好用的打分控件.在项目中可以直接使用,特别简单.下面直接上图: 效果图 实现原理 其实就是自定义View继承LinearLayout ,然后里面动态加了五个ImageView. 实现代码,有详细的注释 在attrs中声明的可以在xml中设置的变量 <declare-styleable name="

  • Android自定义View仿支付宝输入六位密码功能

    跟选择银行卡界面类似,也是用一个PopupWindow,不过输入密码界面是一个自定义view,当输入六位密码完成后用回调在Activity中获取到输入的密码并以Toast显示密码.效果图如下: 自定义view布局效果图及代码如下: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/

  • Android自定义View实现拖动选择按钮

    本文为大家分享了Android实现拖动选择按钮的具体代码,供大家参考,具体内容如下 效果图 View代码 第一步:自定义属性 <declare-styleable name="DragView"> <attr name="icon_drag" format="reference"/> <attr name="color_circle" format="color"/> &

  • Android自定义View实现分段选择按钮的实现代码

    首先演示下效果,分段选择按钮,支持点击和滑动切换. 视图绘制过程中,要执行onMeasure.onLayout.onDraw等方法,这也是自定义控件最常用到的几个方法. onMeasure:测量视图的大小,可以根据MeasureSpec的Mode确定父视图和子视图的大小. onLayout:确定视图的位置 onDraw:绘制视图 这里就不做过多的介绍,主要介绍本控件涉及的到的部分. 1.1 获取item大小.起始位置 @Override protected void onMeasure(int

  • android自定义View圆圈拖动

    本文实例为大家分享了android自定义View圆圈拖动的具体代码,供大家参考,具体内容如下 问题: 1 . 累加问题:"点击坐标"坐标在移动时必须改变位置,不然将导致累加过载 2. 圆形改变问题,每次刷新时圆必将改变位置 3. 图片平移:圆在移动时只要 public class MovingBlockView extends View { //画笔 Paint paint = new Paint(); Region circleRegion; Path circlePath; pri

  • Android自定义View实现拖动自动吸边效果

    本文实例为大家分享了Android自定义View实现拖动自动吸边的具体代码,供大家参考,具体内容如下 自定义View,一是为了满足设计需求,二是开发者进阶的标志之一.随心所欲就是我等奋斗的目标!!! 效果 实现逻辑 明确需求 1.实现控件跟随手指拖动2.实现控件自动贴边 整理思路 1.既然要实现控件拖动,那么就离不开onTouchEvent()这个方法,需要监听里面的按下和滑动事件.2. 要实现自动贴边,需要监听onTouchEvent()中手指离开屏幕事件.对于贴边的过程,我们用属性动画来解决

  • Android自定义view实现拖动小球移动

    Android应用界面中可以看得见的都是由一个个的View所组成的,几乎所有的可视的控件都是基于View写的.在View中提供了对touch也就是手势的捕获和传递,我们可以对View里面手势的重写来达到我们所需要的特性.比如说我们现在要做一款游戏,内容很简单,就是要实现让如图所示的一个黑色的小球在根据手指移动而在手机屏幕内移动. 我们可以重写View里面的public boolean onTouchEvent(MotionEvent event)方法,来获取到所有的手势操作,再从中选择出所需要的

  • Android自定义View圆形和拖动圆跟随手指拖动

    单纯的自定义一个圆非常简单 只需要几步就完成 拖动圆添加实现触摸事件即可 我在第一次自定义View圆遇到的小问题: 1.拖动圆的话在xml里面设置的自定义圆的宽和高是它能活动的空间的大小 不是圆控件的大小 如果你定义了100dp 拖动它的时候超过100dp这个距离这个圆就会看不见 就像下面这样 如果想活动于整个屏幕直接给宽和高match_parent属性就好了 2.在布局里自定的view会提示编译 点击Build编译一下就好了 下面开始写代码: 先是单纯的创建一个圆形 创建一个类继承View 实

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

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

  • Android自定义View实现照片裁剪框与照片裁剪功能

    本文所需要实现的就是这样一种有逼格的效果: 右上角加了个图片框,按下确定可以裁剪正方形区域里的图片并显示在右上角. 实现思路: 1:首先需要自定义一个ZoomImageView来显示我们需要的图片,这个View需要让图片能够以合适的位置展现在当前布局的图片展示区域内(合适的位置值的是:如果图片长度大于屏幕,则压缩图片长度至屏幕宽度,高度等比压缩并居中显示,如果图片高度大于屏幕,则压缩图片高度至屏幕高度,长度等比压缩并居中显示.): 2:然后需要实现这个拖动的框框,该框框实现的功能有四点:拖动.扩

  • Android自定义View实现支付宝支付成功-极速get花式Path炫酷动画

    本文手把手教你图片->SVG->Path的姿势.. 从此酷炫Path动画,如此简单. 效果先随便上几个图,以后你找到的图有多精彩,gif就有多精彩: 随便搜了一个铅笔画的图,丢进去 随手复制的二维码icon 来自大佬wing的铁塔 前文回顾 这里简单回顾一下前文,GIF如下图: PathAnimView接受的唯一数据源是Path(给我一个Path,还你一个动画View) 所以内置了几种将别的资源->Path的方法: 直接传string.(A-Z,0-9 "." &qu

随机推荐