仿荷包投资的滑块
来源:互联网 发布:欧元符号 mac 编辑:程序博客网 时间:2024/04/28 20:32
遇到个需要仿荷包这个滑块的需求
第一想法使用seekbar来实现,结果android:tickMark属性需要API24以上,瞬间无语了,API24的用户目前又有几个呢?
然后想自定义seekbar,结果做出来后拖动的时候一闪一闪的,没有中间过程。
突然想起鸿神的一篇文章里有个拖动控件的ViewDragHelper,http://blog.csdn.net/lmj623565791/article/details/46858663;
稍微修改一下不就是我所需要的吗,我把它里面的多余的去掉,就留了一个回弹的view,然后修改了下回弹的位置,并且用canvas画出几个圆点,大功告成。
先贴上我的布局文件,中间那条线是单独的一个view
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="10dp"> <View android:layout_width="match_parent" android:layout_height="3dp" android:layout_centerVertical="true" android:background="@color/colorAccent" /> <com.tshouyi.vdhdemo.VDHLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerVertical="true" android:orientation="vertical"> <TextView android:layout_width="40dp" android:layout_height="40dp" android:layout_gravity="left" android:background="@mipmap/bg" android:clickable="true" android:gravity="center" android:text="back" /> </com.tshouyi.vdhdemo.VDHLayout></RelativeLayout>
代码注释也很详细了,没注释的地方我也不知道
package com.tshouyi.vdhdemo;import android.animation.ValueAnimator;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Point;import android.support.v4.widget.ViewDragHelper;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.widget.LinearLayout;/** * Created by zxy on 2016/11/11. */public class VDHLayout extends LinearLayout { private ViewDragHelper mDragger; private View mAutoBackView; private Point[] mAutoBackOriginPos = { new Point(0, 0), new Point(0, 0), new Point(0, 0), new Point(0, 0), new Point(0, 0), };//5个原点坐标数组初始值 public VDHLayout(Context context, AttributeSet attrs) { super(context, attrs); setWillNotDraw(false);//没这个方法就不执行onDraw,我也不知道为什么 //1、创建实例 mDragger = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback()//3、实现ViewDragHelper.CallCack相关方法 { /** * 如果子View不消耗事件(clickable=false),那么整个手势(DOWN-MOVE*-UP)都是直接进入onTouchEvent,在onTouchEvent的DOWN的时候就确定了captureView。 * 如果消耗事件,那么就会先走onInterceptTouchEvent方法,判断是否可以捕获,而在判断的过程中会去判断另外两个回调的方法: * getViewHorizontalDragRange和getViewVerticalDragRange,只有这两个方法返回大于0的值才能正常的捕获。 */ @Override public boolean tryCaptureView(View child, int pointerId) {//tryCaptureView如果返回ture则表示可以捕获该view //mEdgeTrackerView禁止直接移动 return child == mAutoBackView; } /** * clampViewPositionHorizontal,clampViewPositionVertical可以在该方法中对child移动的边界进行控制, * left , top 分别为即将移动到的位置,以下代码表示内部移动效果 */ @Override public int clampViewPositionHorizontal(View child, int left, int dx) { final int leftBound = getPaddingLeft(); final int rightBound = getWidth() - mAutoBackView.getWidth() - leftBound; final int newLeft = Math.min(Math.max(left, leftBound), rightBound); return newLeft; } @Override public int clampViewPositionVertical(View child, int top, int dy) { return mAutoBackOriginPos[0].y;//水平滑动,y是固定的 } //手指释放的时候回调 @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { //mAutoBackView手指释放时可以自动回去 if (releasedChild == mAutoBackView) { //判断不同范围回到最近的圆点 if (mAutoBackView.getLeft() < mAutoBackOriginPos[1].x / 2) { mDragger.settleCapturedViewAt(mAutoBackOriginPos[0].x, mAutoBackOriginPos[0].y); } else if (mAutoBackView.getLeft() < 3 * mAutoBackOriginPos[1].x / 2) { mDragger.settleCapturedViewAt(mAutoBackOriginPos[1].x, mAutoBackOriginPos[0].y); } else if (mAutoBackView.getLeft() < 5 * mAutoBackOriginPos[1].x / 2) { mDragger.settleCapturedViewAt(mAutoBackOriginPos[2].x, mAutoBackOriginPos[0].y); } else if (mAutoBackView.getLeft() < 7 * mAutoBackOriginPos[1].x / 2) { mDragger.settleCapturedViewAt(mAutoBackOriginPos[3].x, mAutoBackOriginPos[0].y); } else { mDragger.settleCapturedViewAt(mAutoBackOriginPos[4].x, mAutoBackOriginPos[0].y); } invalidate(); } } @Override public int getViewHorizontalDragRange(View child) { return getMeasuredWidth() - child.getMeasuredWidth(); } @Override public int getViewVerticalDragRange(View child) { return getMeasuredHeight() - child.getMeasuredHeight(); } }); } // 2、触摸相关方法 @Override public boolean onInterceptTouchEvent(MotionEvent event) { return mDragger.shouldInterceptTouchEvent(event);//决定我们是否应该拦截当前的事件 } int position; @Override public boolean onTouchEvent(MotionEvent event) { if (event.getX() > mAutoBackView.getLeft() && event.getX() < mAutoBackView.getRight()) {//按下时在滑块范围内说明要拖动 mDragger.processTouchEvent(event);//处理触摸事件 } else {//else滑动滑块到触摸位置最近的圆点 if (event.getX() - 60 < mAutoBackOriginPos[1].x / 2) { //点击该范围移动到第一个点,60是什么我也不知道,不要这个就点不准 position = 0; } else if (event.getX() - 60 < 3 * mAutoBackOriginPos[1].x / 2) { position = mAutoBackOriginPos[1].x; } else if (event.getX() - 60 < 5 * mAutoBackOriginPos[1].x / 2) { position = 2 * mAutoBackOriginPos[1].x; } else if (event.getX() - 60 < 7 * mAutoBackOriginPos[1].x / 2) { position = 3 * mAutoBackOriginPos[1].x; } else { position = 4 * mAutoBackOriginPos[1].x; } //1.调用ofInt(int...values)方法创建ValueAnimator对象 int pNow = mAutoBackView.getLeft(); ValueAnimator mAnimator = ValueAnimator.ofInt(pNow, position); //2.为目标对象的属性变化设置监听器 mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { // 3.为目标对象的属性设置计算好的属性值 int animatorValue = (int) animation.getAnimatedValue(); MarginLayoutParams marginLayoutParams = (MarginLayoutParams) mAutoBackView.getLayoutParams(); marginLayoutParams.leftMargin = animatorValue; mAutoBackView.setLayoutParams(marginLayoutParams); } }); //4.设置动画的持续时间、是否重复及重复次数等属性 mAnimator.setDuration(Math.abs(pNow - position) * 2); mAnimator.setRepeatCount(0); mAnimator.setRepeatMode(ValueAnimator.REVERSE); //5.为ValueAnimator设置目标对象并开始执行动画 mAnimator.setTarget(mAutoBackView); mAnimator.start(); invalidate(); } return true; } @Override public void computeScroll() { if (mDragger.continueSettling(true)) { invalidate(); } } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); //保存5个原点的位置信息(左边缘坐标),不懂的参考图片 for (int i = 0; i < 5; i++) { mAutoBackOriginPos[i].x = i * ((r - l) - (mAutoBackView.getRight() - mAutoBackView.getLeft())) / 4; mAutoBackOriginPos[i].y = mAutoBackView.getTop(); } } @Override protected void onFinishInflate() { super.onFinishInflate(); mAutoBackView = getChildAt(0);//加载view } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Paint paint = new Paint(); paint.setColor(Color.BLUE); paint.setAntiAlias(true); //画圆点 for (int i = 0; i < 5; i++) { canvas.drawCircle(mAutoBackOriginPos[i].x + (mAutoBackView.getRight() - mAutoBackView.getLeft()) / 2, mAutoBackOriginPos[i].y + (mAutoBackView.getBottom() - mAutoBackView.getTop()) / 2, 15, paint); } }}
不懂的再看一下这张图吧
好了,就这样吧。
顺便把另外一种自定义seek利用seek的进度的方式贴上,原理就是通过改变seekbar的进度来滑动到指定位置。
先看xml文件,两个seekbar重合,上面seekbar个仅仅是为了得到圆点,也就是将Base.Widget.AppCompat.SeekBar.Discrete重新定义了一下,第二个的最大值设置为200
<RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="50dp" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true"> <SeekBar android:id="@+id/seekBar2" style="@style/Base.Widget.AppCompat.SeekBar.Seek" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerVertical="true" android:max="4" android:thumb="@null" /> <SeekBar android:id="@+id/seekBar" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_centerVertical="true" android:max="200" android:progress="0" android:thumb="@mipmap/ic_launcher" /> </RelativeLayout>
接下来是自定义的样式
<style name="Base.Widget.AppCompat.SeekBar.Seek"> <item name="tickMark">@drawable/seekbar</item> </style>
引用的shape文件
<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> <size android:width="12dp" android:height="12dp" /> <solid android:color="@android:color/holo_red_dark" /></shape>
activity也很简单,自己看吧
public class MainActivity extends AppCompatActivity { private SeekBar seekBar; boolean check = false; int pro;//用来控制滑动时触发的onProgressChanged不进行滑动 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); seekBar = (SeekBar) findViewById(R.id.seekBar); SeekBar seekBar2 = (SeekBar) findViewById(R.id.seekBar2); seekBar2.setEnabled(false);//去除重叠的后面个seekbar的影响 seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(final SeekBar seekBar, int i, boolean b) { if (pro==0||pro == seekBar.getProgress() || pro - 1 == seekBar.getProgress()|| pro+ 1 == seekBar.getProgress() ) { //变化值为1的一般不是滑动触发的 final int progress = seekBar.getProgress(); pro = progress; if (progress < 25) { new Handler().postDelayed(new Runnable() { @Override public void run() { if (progress != 0) seekBar.setProgress(progress - 1); } }, 10); } else if (progress < 50) { new Handler().postDelayed(new Runnable() { @Override public void run() { seekBar.setProgress(progress + 1); } }, 10); } else if (progress < 75) { new Handler().postDelayed(new Runnable() { @Override public void run() { if (progress != 50) seekBar.setProgress(progress - 1); } }, 10); } else if (progress < 100) { new Handler().postDelayed(new Runnable() { @Override public void run() { seekBar.setProgress(progress + 1); } }, 10); } else if (progress < 125) { new Handler().postDelayed(new Runnable() { @Override public void run() { if (progress != 100) seekBar.setProgress(progress - 1); } }, 10); } else if (progress < 150) { new Handler().postDelayed(new Runnable() { @Override public void run() { seekBar.setProgress(progress + 1); } }, 10); } else if (progress < 175) { new Handler().postDelayed(new Runnable() { @Override public void run() { if (progress != 150) seekBar.setProgress(progress - 1); } }, 10); } else if (progress < 200) { new Handler().postDelayed(new Runnable() { @Override public void run() { seekBar.setProgress(progress + 1); } }, 10); } } } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(final SeekBar seekBar) { pro=seekBar.getProgress(); seekBar.setProgress(seekBar.getProgress() - 1); } }); }}
最后效果
没怎么写博客,里面问题很多,欢迎指正
0 0
- 仿荷包投资的滑块
- 仿荷包动画
- 简单高仿荷包注册进度条
- 仿荷包启动动画,金钱掉落,钱包回弹
- 仿网易新闻标题栏滑块-绘制的三角滑块
- 是什么让你的荷包总是那么干瘪...
- 移动端区间滑块,仿 上一篇pc端的
- 计算机的投资:量化投资
- 荷包金融怎么升级?
- 模仿荷包启动动画
- 自己仿写一个ucosii(二) 任务控制块的简析
- 这块“不务正业”的仿神经芯片居然学会了谱曲
- 超仿 网易新闻android客户端 滑动Menu 滑动广告和标题滑块
- jquery仿淘宝网登录拖动滑块验证码效果-- 一天一篇文章
- 北斗的投资哲学、投资理念及投资策略
- 投资理财:货币市场基金的投资技巧
- 数量投资对传统投资的优越性
- [投资笔记]xnby的投资日志-续篇
- Python-Django入门
- java调用http接口
- openssl、x509、crt、cer、key、csr、ssl、tls 这些都是什么鬼?
- android主机强制设置speaker为usb speaker
- HDU 1214 圆桌会议 【找规律】
- 仿荷包投资的滑块
- nodejs如何调用动态链接库(dll)呢?写一个addon来处理,写此文抛砖引玉。
- python单元测试unittest
- 好的网站
- Win7+VS2013+opencv3.0.0环境搭建
- 工厂模式——只有例子没有解释的设计模式
- android 获取application和activity下meta-data中的值
- ftp抓包分析
- 期货ctp开源量化平台