getRawX、getRawY与getX、getY以及View中的getScrollX、getScrollY以及Scroller中的startScroll方法

1.getRawX、getRawY与getX、getY的区别

在编写android的自定义控件,或者判断用户手势操作时,往往需要使用MotionEvent中的getRawX()getRawY()getX()getY()取得触摸点在X轴与Y轴上的距离,这四个方法都返回一个float类型的参数,单位为像素(Pixel)。getRawX()getRawY()返回的是触摸点相对于屏幕的位置,而getX()getY()返回的则是触摸点相对于View的位置。

以下两张图直观的表现了这几个方法的区别,在屏幕中央放置了一个Button,并为它注册了OnTouchListener,图中绿圆点为触摸点位置。

注意:这里的正负是以左上角为原点,右边和下边为正,这和下面的scroll内容的滑动相反哦

    

 

2.View中的getScrollX、getScrollY

getScrollX()与getScrollY()的值由调用View的scrollTo(int x, int y)或者scrollBy(int x, int y)产生,其中scrollTo是将View中的内容移动到指定的坐标x、y处,此x、y是相对于

View的左上角,而不是屏幕的左上角。scrollBy(int x, int y)则是改变View中的相对位置,参数x、y为距离上一次的相对位置。

文字解释总是不好理解的,那么我们就直接上图吧,直观一些。

               (图1)                                                         (图2)                                                                (图3)

1.图1中,屏幕中心放置了一个button,而button的内容被放置在了它的左上角。

2.调用button的scrollTo(-100, -100)方法,结果如图2所示,button内的内容被移至相对button左上角(-100,-100)的位置

3.对图2的button调用scrollBy(-100,-100)方法,结果如图3所示,button内的内容被移至相对于图2的(-100,-100)位置

这时的getScrollX()与getScrollY()的值为:

06-15 15:44:56.072  20471-20471/com.test.yangy.studiotest V/ScrollActivity﹕ btn scroll X=-200
06-15 15:44:56.072  20471-20471/com.test.yangy.studiotest V/ScrollActivity﹕ btn scroll Y=-200

值得注意的是,当View中的内容向右移动时,getScrollX()的值为负数,同理,向scrollTo与scrollBy的x中传入负数,view中的内容向右移动,反之向左。

当View中的内容向下移动时,getScrollY()的值为负数,同理,向scrollTo与scrollBy的y中传入负数,view中的内容向下移动,反之向上。



******************************************************************************************

Scroller中的startScroll方法

注意dx和dy是偏移量,不是重

API如下:

public void startScroll (int startX, int startY, int dx, int dy)

  以提供的起始点和将要滑动的距离开始滚动。滚动会使用缺省值250ms作为持续时间。

      参数

          startX 水平方向滚动的偏移值,以像素为单位。正值表明滚动将向左滚动

  startY 垂直方向滚动的偏移值,以像素为单位。正值表明滚动将向上滚动

  dx 水平方向滑动的距离,正值会使滚动向左滚动

  dy 垂直方向滑动的距离,正值会使滚动向上滚动

我的理解是:

startX 表示起点在水平方向到原点的距离(可以理解为X轴坐标,但与X轴相反),正值表示在原点左边,负值表示在原点右边。

dx 表示滑动的距离,正值向左滑,负值向右滑。

这与我们感官逻辑相反,需要注意。


-------------------------------------

使用后记得调用Invalidate():

  1. scrollTo(mScroller.getCurrX(), 0);  
  2.         Invalidate();  
还得重写View的computeScroll方法:
    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            // Get current x and y positions
            int currX = mScroller.getCurrX();
            int currY = mScroller.getCurrY();
            scrollTo(currX, currY);
            postInvalidate();
        }
        if (isMenuOpen()) {
            currentState = STATE_OPEND;
        } else if (isMenuClosed()) {
            currentState = STATE_CLOSED;
        }
    }


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个基于 Android 的自定义悬浮窗页面磁吸四周工具类的示例代码。 首先,我们需要定义一个 FloatingView 类,它继承自 FrameLayout,并实现了 View.OnTouchListener 接口。这个类表示悬浮窗页面,可以包含任意的子 View。 ``` public class FloatingView extends FrameLayout implements View.OnTouchListener { private int mLastX; private int mLastY; private int mStartX; private int mStartY; private int mScreenWidth; private int mScreenHeight; public FloatingView(Context context) { this(context, null); } public FloatingView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public FloatingView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { setOnTouchListener(this); mScreenWidth = getResources().getDisplayMetrics().widthPixels; mScreenHeight = getResources().getDisplayMetrics().heightPixels; } @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mStartX = (int) event.getRawX(); mStartY = (int) event.getRawY(); mLastX = mStartX; mLastY = mStartY; break; case MotionEvent.ACTION_MOVE: int dx = (int) (event.getRawX() - mLastX); int dy = (int) (event.getRawY() - mLastY); int x = getX() + dx; int y = getY() + dy; if (x < 0) { x = 0; } if (x > mScreenWidth - getWidth()) { x = mScreenWidth - getWidth(); } if (y < 0) { y = 0; } if (y > mScreenHeight - getHeight()) { y = mScreenHeight - getHeight(); } setX(x); setY(y); mLastX = (int) event.getRawX(); mLastY = (int) event.getRawY(); break; case MotionEvent.ACTION_UP: if (Math.abs(event.getRawX() - mStartX) < 5 && Math.abs(event.getRawY() - mStartY) < 5) { performClick(); } break; } return true; } } ``` 接下来,我们编写一个辅助类,用于将悬浮窗页面磁吸到屏幕的四周。该类需要维护一个 FloatingView 对象,以及一些悬浮窗的位置信息。 ``` public class FloatingViewHelper { private static final int MARGIN = 10; private FloatingView mFloatingView; private int mScreenWidth; private int mScreenHeight; private int mLeft; private int mTop; private int mRight; private int mBottom; public FloatingViewHelper(Context context, FloatingView floatingView) { mFloatingView = floatingView; mScreenWidth = context.getResources().getDisplayMetrics().widthPixels; mScreenHeight = context.getResources().getDisplayMetrics().heightPixels; } public void attachToWindow() { WindowManager.LayoutParams params = new WindowManager.LayoutParams(); params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; params.format = PixelFormat.RGBA_8888; params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; params.gravity = Gravity.TOP | Gravity.LEFT; params.width = WindowManager.LayoutParams.WRAP_CONTENT; params.height = WindowManager.LayoutParams.WRAP_CONTENT; mFloatingView.setLayoutParams(params); mFloatingView.setOnTouchListener(mFloatingView); WindowManager wm = (WindowManager) mFloatingView.getContext().getSystemService(Context.WINDOW_SERVICE); wm.addView(mFloatingView, params); } public void detachFromWindow() { WindowManager wm = (WindowManager) mFloatingView.getContext().getSystemService(Context.WINDOW_SERVICE); wm.removeView(mFloatingView); } public void snapToEdge() { int centerX = (mLeft + mRight) / 2; int centerY = (mTop + mBottom) / 2; if (centerX < mScreenWidth / 2) { mFloatingView.setX(0 + MARGIN); mLeft = 0; mRight = mLeft + mFloatingView.getWidth(); } else { mFloatingView.setX(mScreenWidth - mFloatingView.getWidth() - MARGIN); mRight = mScreenWidth; mLeft = mRight - mFloatingView.getWidth(); } if (centerY < mScreenHeight / 2) { mFloatingView.setY(0 + MARGIN); mTop = 0; mBottom = mTop + mFloatingView.getHeight(); } else { mFloatingView.setY(mScreenHeight - mFloatingView.getHeight() - MARGIN); mBottom = mScreenHeight; mTop = mBottom - mFloatingView.getHeight(); } } public void updatePosition() { mLeft = (int) mFloatingView.getX(); mTop = (int) mFloatingView.getY(); mRight = mLeft + mFloatingView.getWidth(); mBottom = mTop + mFloatingView.getHeight(); } } ``` 最后,我们可以在 Activity 使用这个辅助类来实现悬浮窗的磁吸效果。 ``` public class MainActivity extends AppCompatActivity { private FloatingView mFloatingView; private FloatingViewHelper mFloatingViewHelper; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mFloatingView = new FloatingView(this); mFloatingView.setBackgroundColor(Color.YELLOW); mFloatingViewHelper = new FloatingViewHelper(this, mFloatingView); mFloatingViewHelper.attachToWindow(); } @Override protected void onDestroy() { super.onDestroy(); mFloatingViewHelper.detachFromWindow(); } @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if (hasFocus) { mFloatingViewHelper.snapToEdge(); mFloatingViewHelper.updatePosition(); } } } ``` 这里,我们在 onCreate 方法创建了一个 FloatingView 对象,并将其添加到 Activity 的界面。然后,我们创建了一个 FloatingViewHelper 对象,将其附加到 FloatingView 上,并将其添加到 WindowManager 显示。在 onDestroy 方法,我们从 WindowManager 移除了 FloatingView。 在 onWindowFocusChanged 方法,我们在 Activity 获取焦点时调用了 snapToEdge 方法,将 FloatingView 磁吸到屏幕的四周。我们还调用了 updatePosition 方法,更新了悬浮窗的位置信息。这样,我们就实现了一个简单的悬浮窗页面磁吸四周工具类。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值