Android自定义可拖动的悬浮按钮
在页面上随意拖动的按钮
public class MoveScaleRotateView extends RelativeLayout {
private Context mContext;
//默认的触摸点ID
private static final int INVALID_POINTER_ID = -;
//子View上的两个手指的触摸点ID
private int mChildPtrID1 = INVALID_POINTER_ID, mChildPtrID2
= INVALID_POINTER_ID;
//父View上的两个手指的触摸点ID
private int mPtrID1 = INVALID_POINTER_ID, mPtrID2 = INVALID_POINTER_ID;
//父布局的Event事件
private MotionEvent mEvent;
//记录点击在子View上的x和y坐标
private float mChildActionDownX = ;
private float mChildActionDownY = ;
//记录点击在父View上的第一个点和第二个点的x和y坐标
private float mActionDownX1 = ;
private float mActionDownX2 = ;
private float mActionDownY1 = ;
private float mActionDownY2 = ;
//初始的旋转角度
private float mDefaultAngle;
//当前旋转角度
private float mAngle;
//记录原始落点的时候两个手指之间的距离
private float oldDist = ;
//是否是点击
private boolean isCheck=false;
//测试View
private View view;
private DisplayMetrics dm;
//初始化操作
private void init(final Context context) {
mContext = context;
view = View.inflate(context, R.layout.layout_test_rela_view, null);
addView(view);
dm = new DisplayMetrics();
dm = getResources().getDisplayMetrics();
view.setX(dm.widthPixels-);
view.setY(dm.heightPixels/);
this.setFocusableInTouchMode(true);
view.setOnTouchListener(new OnTouchListener() {
private float lastY;
private float lastX;
private float rawY;
private float rawX;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch ( event.getAction() & MotionEvent.ACTION_MASK ) {
case MotionEvent.ACTION_DOWN:
mChildPtrID1 = event.getPointerId(event.getActionIndex());
if ( mEvent != null ) {
mChildActionDownX = mEvent.getX(event.findPointerIndex(mChildPtrID1))
- view.getX();
mChildActionDownY = mEvent.getY(event.findPointerIndex(mChildPtrID1))
- view.getY();
rawX = (event.getRawX());
rawY = (event.getRawY());
lastX = rawX;
lastY = rawY;
}else {
return false;
}
break;
case MotionEvent.ACTION_MOVE:
if ( mEvent != null ) {
// try {
float x1 = mEvent.getX(mEvent.findPointerIndex(mChildPtrID1));
float y1 = mEvent.getY(mEvent.findPointerIndex(mChildPtrID1));
if (x1 - mChildActionDownX<=){
view.setX();
}else if (x1 - mChildActionDownX>=dm.widthPixels-){
view.setX( dm.widthPixels-);
}else{
view.setX(x1 - mChildActionDownX);
}
if (y1 - mChildActionDownY<=){
view.setY();
}else if (y1 - mChildActionDownY>=dm.heightPixels-){
view.setY( dm.heightPixels-);
}else{
view.setY(y1 - mChildActionDownY);
}
lastX = (event.getRawX());
lastY = (event.getRawY());
Log.v("sadadas",lastX+"--"+lastY+"--"+x1+"--"+y1);
// }catch (Exception e){}
}else {
return false;
}
break;
case MotionEvent.ACTION_UP:
mChildPtrID1 = INVALID_POINTER_ID;
if (rawX-lastX<=&&rawX-lastX>=-
&&rawY-lastY>=-&&rawY-lastY<=){
}
break;
case MotionEvent.ACTION_CANCEL:
mChildPtrID1 = INVALID_POINTER_ID;
mChildPtrID2 = INVALID_POINTER_ID;
break;
}
return true;
}
});
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mEvent = event;
switch ( event.getAction() & MotionEvent.ACTION_MASK ) {
case MotionEvent.ACTION_DOWN:
mPtrID1 = event.getPointerId(event.getActionIndex());
mActionDownX1 = event.getX(event.findPointerIndex(mPtrID1));
mActionDownY1 = event.getY(event.findPointerIndex(mPtrID1));
break;
case MotionEvent.ACTION_POINTER_DOWN:
//非第一个触摸点按下
mPtrID2 = event.getPointerId(event.getActionIndex());
mActionDownX2 = event.getX(event.findPointerIndex(mPtrID2));
mActionDownY2 = event.getY(event.findPointerIndex(mPtrID2));
oldDist = spacing(event, mPtrID1, mPtrID2);
break;
case MotionEvent.ACTION_MOVE:
if ( mPtrID1 != INVALID_POINTER_ID && mPtrID2 != INVALID_POINTER_ID ) {
float x1 = , x2 = , y1 = , y2 = ;
x1 = event.getX(event.findPointerIndex(mPtrID1));
y1 = event.getY(event.findPointerIndex(mPtrID1));
x2 = event.getX(event.findPointerIndex(mPtrID2));
y2 = event.getY(event.findPointerIndex(mPtrID2));
//在这里处理旋转逻辑
mAngle = angleBetweenLines(mActionDownX1, mActionDownY1, mActionDownX2,
mActionDownY2, x1, y1, x2, y2) + mDefaultAngle;
view.setRotation(mAngle);
//在这里处理缩放的逻辑
//处理缩放模块
float newDist = spacing(event, mPtrID1, mPtrID2);
float scale = newDist / oldDist;
if ( newDist > oldDist + ) {
zoom(scale, view);
oldDist = newDist;
}
if ( newDist < oldDist - ) {
zoom(scale, view);
oldDist = newDist;
}
}
break;
case MotionEvent.ACTION_UP:
mPtrID1 = INVALID_POINTER_ID;
break;
case MotionEvent.ACTION_POINTER_UP:
//非第一个触摸点抬起
mPtrID2 = INVALID_POINTER_ID;
mDefaultAngle = mAngle;
break;
case MotionEvent.ACTION_CANCEL:
mPtrID1 = INVALID_POINTER_ID;
mPtrID2 = INVALID_POINTER_ID;
break;
}
return false;
}
//对控件进行缩放操作
private void zoom(float scale, View view) {
int w = view.getWidth();
int h = view.getHeight();
view.setLayoutParams(new RelativeLayout.LayoutParams(( int ) (w * scale), ( int ) (h * scale)));
}
/**
* 计算两点之间的距离
*
* @param event
* @return 两点之间的距离
*/
private float spacing(MotionEvent event, int ID1, int ID2) {
float x = event.getX(ID1) - event.getX(ID2);
float y = event.getY(ID1) - event.getY(ID2);
return ;
}
/**
* 计算刚开始触摸的两个点构成的直线和滑动过程中两个点构成直线的角度
*
* @param fX 初始点一号x坐标
* @param fY 初始点一号y坐标
* @param sX 初始点二号x坐标
* @param sY 初始点二号y坐标
* @param nfX 终点一号x坐标
* @param nfY 终点一号y坐标
* @param nsX 终点二号x坐标
* @param nsY 终点二号y坐标
* @return 构成的角度值
*/
private float angleBetweenLines(float fX, float fY, float sX, float sY, float nfX, float nfY, float nsX, float nsY) {
float angle1 = ( float ) Math.atan2((fY - sY), (fX - sX));
float angle2 = ( float ) Math.atan2((nfY - nsY), (nfX - nsX));
float angle = (( float ) Math.toDegrees(angle1 - angle2)) % ;
if ( angle < -.f ) angle += 360.0f;
if ( angle > .f ) angle -= 360.0f;
return -angle;
}
public MoveScaleRotateView(Context context) {
super(context);
init(context);
}
public MoveScaleRotateView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public MoveScaleRotateView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
@TargetApi( Build.VERSION_CODES.LOLLIPOP )
public MoveScaleRotateView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context);
}
/**
* 测试用 显示Toast
*
* @param msg
*/
private void showToast(String msg) {
Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
}
/**
* 测试用 打印log
*
* @param log
*/
private void log(String log) {
Log.e("HHHHHHHHHH", log);
}
/**
* 测试用 打印log 指定TAG
*
* @param log
* @param tag
*/
private void log(String log, String tag) {
Log.e(tag, log);
}
}
按钮布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="70dp"
android:layout_height="70dp"
android:focusableInTouchMode="true"> <TextView
android:text="取件"
android:focusableInTouchMode="true"
android:layout_centerInParent="true"
android:background="@drawable/shape_yellow"
android:gravity="center"
android:textColor="#ffffff"
android:textSize="15sp"
android:layout_width="50dp"
android:layout_height="50dp" /> </RelativeLayout>
按钮背景设置:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"> <corners android:radius="360dp"></corners>
<solid android:color="#FCDB12"></solid> </shape>
Android自定义可拖动的悬浮按钮的更多相关文章
- Android FloatingActionButton(FAB) 悬浮按钮
FloatingActionButton 悬浮按钮 ...
- Android自定义Seekbar拖动条式样
SeekBar拖动条可以由用户控制,进行拖动操作.比如,应用程序中用户需要对音量进行控制,就可以使用拖动条来实现. 1.SeekBar控件的使用 1.1SeekBar常用属性 SeekBar的常用属性 ...
- Android -- 自定义带进度条的按钮
1. 实现了一个带进度条的按钮,完成后显示提示信息,并设置按钮为不可再次被点击
- Android 自定义组件之 带有悬浮header的listview
最近做项目遇到一个需求,要做一个带有悬浮header的listview,即,当listview滑动时,header消失,静止时header浮现. 这个需求看似简单,实际做起来还是会遇到不少的困难,特此 ...
- android悬浮按钮(Floating action button)的两种实现方法
原文: http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1028/1857.html 最近android中有很多新的设计规范被引入 ...
- Android用悬浮按钮实现翻页效果
今天给大家分享下自己用悬浮按钮点击实现翻页效果的例子. 首先,一个按钮要实现悬浮,就要用到系统顶级窗口相关的WindowManager,WindowManager.LayoutParams.那么在An ...
- Android自定义View带有删除按钮的EditText
转载请注明出处http://blog.csdn.net/xiaanming/article/details/11066685 今天给大家带来一个很实用的小控件ClearEditText,就是在Andr ...
- Android 5.0新控件——FloatingActionButton(悬浮按钮)
Android 5.0新控件--FloatingActionButton(悬浮按钮) FloatingActionButton是5.0以后的新控件,一个悬浮按钮,之所以叫做悬浮按钮,主要是因为自带阴影 ...
- 013 Android ActionFloatingButton悬浮按钮组件与Snackbar组件使用
1.导入ActionFloatingButton组件(点击下载按钮,安装组件) 2,.ImageView图片XML设置 <ImageView android:id="@+id/imag ...
随机推荐
- httpd服务相关实验
实验环境: CentOS6.8 1.连接测试: 在/etc/httpd/conf/httpd.conf telnet 172.16.252.242 80 GET /index.html HTTP/1. ...
- java POP3
package com.skyzoo.Jutil; import java.io.BufferedReader; import java.io.IOException; import java.io. ...
- ajax方法data参数用法的总结
源文件分析: data的传递格式有两种:一是url字符串格式:一种是Json格式,格式分别如上 区别是:当传递的参数中包含 特殊字符如:&时,服务器解析这个参数时就会出错,而必须用encode ...
- 《Java多线程编程核心技术》读后感(四)
将任意对象作为对象监视器 synchronized同步代码块还支持任意对象,使用格式为synchronized(非this对象) package Second; public class Servic ...
- Docker环境下的前后端分离项目部署与运维(七)Redis高速缓存
Redis高速缓存 利用内存保存数据,读写速度远超硬盘:可以减少I/O操作,降低I/O压力. 发红包.抢红包的数据可以存在高速缓存中,加快处理速度,不需要经过数据库 淘宝首页一些优惠活动商品等热数据可 ...
- css样式也技巧
目录 关于iPhone的点击事件绑定无效的处理方法 https://blog.csdn.net/u014477038/article/details/52527194 去掉a.button.input ...
- Untiy ShaderLab 随手记录
最基本形式 (先不考虑Fog) Shader "Nafio/TUnlit"{ Properties { _MainTex("TT",2D) = "wh ...
- codeforces1009G Allowed Letters【贪心+hall定理】
因为是字典序所以贪心选当前能选的最小的,所以问题就在于怎么快速计算当前这个位置能不能选枚举的字母 重排之后的序列是可以和原序列完美匹配的,而完美匹配需要满足hall定理,也就是左边任意k个集合一定和右 ...
- [Xcode 实际操作]七、文件与数据-(3)创建文本文件、属性列表文件、图片文件
目录:[Swift]Xcode实际操作 本文将演示如何创建各种类型的文件. 在项目导航区,打开视图控制器的代码文件[ViewController.swift] import UIKit class V ...
- 剑指Offer的学习笔记(C#篇)-- 序列化二叉树
题目描述 请实现两个函数,分别用来序列化和反序列化二叉树 一 . 理解题意 二叉树的序列化,是将一个结构化的东西变成扁平化的字符串,序列化二叉树或者是反序列化二叉树就是二叉树和扩展二叉树遍历序列之间的 ...