Activity和Window的View的移动的一些思考与体会,腾讯悬浮小火箭的实现策略_第1页
Activity和Window的View的移动的一些思考与体会,腾讯悬浮小火箭的实现策略_第2页
Activity和Window的View的移动的一些思考与体会,腾讯悬浮小火箭的实现策略_第3页
Activity和Window的View的移动的一些思考与体会,腾讯悬浮小火箭的实现策略_第4页
Activity和Window的View的移动的一些思考与体会,腾讯悬浮小火箭的实现策略_第5页
已阅读5页,还剩19页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Activity和Window的View的移动的一些思考与体会,腾讯悬浮小火箭的实现策略事实上写这个也是因为自己实际在项目中用到了才会去研究已经写文章,对于View的移动,其实说实话,已经有很多文章了,既然如此的话,那我实在是不好意思再去重复的讲解,但是和Window的View还是有一些区别的,接下来,我会实际的讲解一下这些区别已经坐标函数的计算方法,当然,最后再讲一下如何实现腾讯的悬浮小火箭,这些都是比较好的干货,我也相信大家都是比较喜欢的,而你在本文中将学会使用View的移动计算坐标,有三个目录1.Activity中View的移动2.Window中View的移动3.实现腾讯悬浮小火箭我们首

2、先新建一个项目ViewAndWindow来实现三个按钮作为这三个功能的三个Activity跳转,三个Activity分别是ActivityActivityWindowActivityTencentActivity所以主布局-activity_layout.xml应该是这么写的<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android=" android:layout_width="match_parent" android:layout

3、_height="match_parent" android:gravity="center" android:orientation="vertical" android:padding="10dp"> <Button android:id="+id/btnActivity" android:layout_width="match_parent" android:layout_height="wrap_content" android:tex

4、t="Activity中View的移动" android:textAllCaps="false" /> <Button android:id="+id/btnWindow" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Window中View的移动" android:textAllCaps="false" />

5、<Button android:id="+id/btnTencent" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="腾讯小火箭" android:textAllCaps="false" /></LinearLayout>不可否认,我们的MainActivty只是作为程序的入口,所以他的代码是十分的简单的package com.lgl.viewa

6、ndwindow;import android.content.Intent;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.Button;public class MainActivity extends AppCompatActivity implements View.OnClickListener private Button btnActivity, btnWindow, btnTencent;

7、 Override protected void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); /初始化View private void initView() btnActivity = (Button) findViewById(R.id.btnActivity); btnActivity.setOnClickListener(this); btnWindow = (Button) find

8、ViewById(R.id.btnWindow); btnWindow.setOnClickListener(this); btnTencent = (Button) findViewById(R.id.btnTencent); btnTencent.setOnClickListener(this); /点击事件 Override public void onClick(View v) switch (v.getId() case R.id.btnActivity: startActivity(new Intent(this, ActivityActivity.class); break; c

9、ase R.id.btnWindow: startActivity(new Intent(this, WindowActivity.class); break; case R.id.btnTencent: startActivity(new Intent(this, TencentActivity.class); break; 而我们的重点也不在这里,而在这些子Activity一.Activity中View的移动实际上,View在Activity上移动,还是要依靠事件去传递,总所周知,View的绘制流程一般都是先onMeasure测量,接下来是onLayout确定位置,最后才是onDraw绘制

10、,所以,我们的更新坐标其实是在onLayout进行的,好吧,说这些再多都不如代码来的实际一点,我们在Activity中写一个ImageView <ImageView android:id="+id/ivDraw" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="mipmap/ic_launcher" />我们就是要对他下手了,是的,就在OnTouchListener中进行,OnTo

11、uchListener回调中有一个MotionEvent类,他封装了我们触摸事件的大部分动作,其中就包括三大将军 switch (event.getAction() /按下 case MotionEvent.ACTION_DOWN: break; /抬起 case MotionEvent.ACTION_UP: break; /移动 case MotionEvent.ACTION_MOVE: break;而我们如果单单只是移动这个View的话,其实是用不到抬起这个UP的动作的,我们要想实现这个View的移动,首先得知道这个View在哪里,所以我们需要先定义两个变量 /起点坐标 private i

12、nt startX, startY;而我们什么时候得到View的初始坐标呢?肯定是在按下这个动作上获取 startX = (int) event.getRawX(); startY = (int) event.getRawY();而这里,肯定就会有人问,这个getX和getRowX有什么区别,其实区别还是挺大的,前者是获取当前父容器的X坐标,后者是相对于整个屏幕的坐标,OK,获取到之后,我们应该干什么?这个时候我们应该使用到MOVE这个动作了,你在拖动,我计算偏移量并且更新这个View的位置,来达到移动的视觉效果,那我们还得定义几个变量首先是你的重点坐标,有始有终/终点坐标 private i

13、nt endX, endY;紧接着,会让终点坐标减去起点坐标,来计算这个偏移量,所以有了偏移量的变量/偏移量 private int dx, dy;所以,我们MOVE的动作里计算公式应该是这样的 endX = (int) event.getRawX(); endY = (int) event.getRawY(); /计算移动偏移量 dx = endX - startX; dy = endY - startY;获取到你移动的偏移量,我们就可以拿到移动后的坐标了,还记得我们在绘制矩形的时候用到的那套公式吗我们直接套用这套公式,其实就可以得到左上右下的坐标了int left = tvAddress.

14、getLeft() + dx;int top = tvAddress.getTop() + dy;int right = tvAddress.getRight() + dx;int bottom = tvAddress.getBottom() + dy;OK,这里,其实有点类似于测量,测量结束之后就可以确定位置了,就得用到我们的onLayout了 /重新部署位置 ivDraw.layout(left, top, right, bottom);到这里,其实很多人就以为走完了的,其实更新完位置之后,你还要把初始位置给初始化一下,也就是赋值成你更新后的坐标点/重新初始化坐标startX = (int

15、) event.getRawX();startY = (int) event.getRawY();对了。记得return true,这里你会问,为什么是true,因为true代表我要消耗掉这个事件,你其他的就不要接收了,你不信的话可以设置一个点击事件看看有没有效果!这里,我们就算大功告成了,如果你想记录这个坐标点,你就会用到UP了,不多说,我们运行看看效果但是这里,还需要优化一下,比如,我移动到边上的时候直接就进去了,我们应该放置这个View超过屏幕,对吧,那我们应该怎么做?我们首先先获取到整个屏幕的宽高 wm = (WindowManager) getSystemService(WINDOW

16、_SERVICE); width = wm.getDefaultDisplay().getWidth(); height = wm.getDefaultDisplay().getHeight();这样,我们通过WindowManager就能直接拿到宽高了,然后我们在移动的时候可以这样做/防止上下 if (top < 0 | bottom > height - 20) return true; /防止左右 if (left < 0 | right > width) return true; 这样,我们就可以直接看到效果了这里的减去20是状态栏的,但是下面的虚拟按键倒是没有

17、考虑进去,不过思路真的可行好了,上面是步骤,我们就直接把代码全部贴出来吧package com.lgl.viewandwindow;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.view.MotionEvent;import android.view.View;import android.view.WindowManager;import android.widget.ImageView;/* * Created by LGL on 2016/7/28. */pu

18、blic class ActivityActivity extends AppCompatActivity private ImageView ivDraw; /起点坐标 private int startX, startY; /终点坐标 private int endX, endY; /偏移量 private int dx, dy; /窗口管理器 private WindowManager wm; /屏幕宽高 private int width, height; Override protected void onCreate(Bundle savedInstanceState) super

19、.onCreate(savedInstanceState); setContentView(R.layout.activity_activity); wm = (WindowManager) getSystemService(WINDOW_SERVICE); width = wm.getDefaultDisplay().getWidth(); height = wm.getDefaultDisplay().getHeight(); ivDraw = (ImageView) findViewById(R.id.ivDraw); ivDraw.setOnTouchListener(new View

20、.OnTouchListener() Override public boolean onTouch(View v, MotionEvent event) switch (event.getAction() case MotionEvent.ACTION_DOWN: startX = (int) event.getRawX(); startY = (int) event.getRawY(); break; case MotionEvent.ACTION_UP: break; case MotionEvent.ACTION_MOVE: endX = (int) event.getRawX();

21、endY = (int) event.getRawY(); /计算移动偏移量 dx = endX - startX; dy = endY - startY; /* *根据偏移量更新位置(重新部署位置) */ int left = ivDraw.getLeft() + dx; int top = ivDraw.getTop() + dy; int right = ivDraw.getRight() + dx; int bottom = ivDraw.getBottom() + dy; /防止上下 if (top < 0 | bottom > height - 20) return t

22、rue; /防止左右 if (left < 0 | right > width) return true; /重新部署位置 ivDraw.layout(left, top, right, bottom); /重新初始化坐标 startX = (int) event.getRawX(); startY = (int) event.getRawY(); break; return true; ); 二.Window中View的移动Activity上毕竟是有迹可循,那Window上呢?其实窗体上逻辑是差不多的,唯一差的,就是那些函数的调用了,OK,我们进入WindowActivity中,

23、先写个Button启动这个Window <Button android:id="+id/showWindow" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Show Window" android:textAllCaps="false" />他所对应的点击事件 /点击事件 showWindow = (Button) findViewById(R.id.sh

24、owWindow); showWindow.setOnClickListener(new View.OnClickListener() Override public void onClick(View v) showMoveWindow(); );而我们这个小节的重点就的照顾一下 showMoveWindow()这个方法了,怎么实现一个Window不是今天的重点,而且也确实没什么可讲的,我就直接上代码了 /窗口管理器 wm = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE); /

25、布局参数 final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(); layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT; layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT; layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | /WindowManager.Layo

26、utParams.FLAG_NOT_TOUCHABLE | 不能触摸 WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; /格式 layoutParams.format = PixelFormat.TRANSLUCENT; /类型 layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE; ivDraw = new ImageView(this); ivDraw.setBackgroundResource(R.mipmap.ic_launcher); /加载view wm.addView(iv

27、Draw, layoutParams);这段代码就能实现一个window了,我们可以看一下我们需要权限哦<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />11我们是直接new了一个ImageView的,但是不妨碍我们使用View的移动,我们直接实现它的触摸事件 /触摸事件 ivDraw.setOnTouchListener(new View.OnTouchListener() Override public boolean onTouch(View v, Motion

28、Event event) switch (event.getAction() case MotionEvent.ACTION_DOWN: break; case MotionEvent.ACTION_MOVE: break; return true; );我这里暂时也只是实现了两个动作,因为作为演示我们的UP确实用不上,我们有了前车之鉴,我们直接定义我们需要的变量吧 /起始坐标 private int startX, startY; /终点坐标 private int endX, endY; /偏移量 private int dx, dy;OK,老套路,在DOWN中,我们只是获取当前的坐标 s

29、tartX = (int) event.getRawX(); startY = (int) event.getRawY();但是移动的时候,获取的就不是左上右下了,而是他的x和y坐标,因为他是window,所以我们用到的是LayoutParams,更新位置也是使用的LayoutParams,他有一个updateViewLayout的方法 endX = (int) event.getRawX(); endY = (int) event.getRawY(); /计算移动偏移量 dx = endX - startX; dy = endY - startY; /* *根据偏移量更新位置(重新部署位置)

30、 */ layoutParams.x += dx; layoutParams.y += dy; /更新位置 wm.updateViewLayout(ivDraw, layoutParams); /重新初始化坐标 startX = (int) event.getRawX(); startY = (int) event.getRawY();当然,最后return true;我们试试而因为他是window的改哪里,他并不需要去做一些超出边距的处理,很nice把这部分代码也全部贴上来package com.lgl.viewandwindow;import android.content.Context

31、;import android.graphics.PixelFormat;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.view.MotionEvent;import android.view.View;import android.view.WindowManager;import android.widget.Button;import android.widget.ImageView;/* * Created by LGL on 2016/7/28. */pu

32、blic class WindowActivity extends AppCompatActivity private Button showWindow; /窗口管理器 private WindowManager wm; /图片 private ImageView ivDraw; /起始坐标 private int startX, startY; /终点坐标 private int endX, endY; /偏移量 private int dx, dy; Override protected void onCreate(Bundle savedInstanceState) super.onC

33、reate(savedIstanceState); setContentView(R.layout.activity_window); /点击事件 showWindow = (Button) findViewById(R.id.showWindow); showWindow.setOnClickListener(new View.OnClickListener() Override public void onClick(View v) showMoveWindow(); ); /显示窗口 private void showMoveWindow() /窗口管理器 wm = (WindowMan

34、ager)getSystemService(Context.WINDOW_SERVICE); /布局参数 final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(); layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT; layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT; layoutParams.flags = WindowManager.Layou

35、tParams.FLAG_NOT_FOCUSABLE | /WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | 不能触摸 WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; /格式 layoutParams.format = PixelFormat.TRANSLUCENT; /类型 layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE; ivDraw = new ImageView(this); ivDraw.setBackgroundResou

36、rce(R.mipmap.ic_launcher); /触摸事件 ivDraw.setOnTouchListener(new View.OnTouchListener() Override public boolean onTouch(View v, MotionEvent event) switch (event.getAction() case MotionEvent.ACTION_DOWN: startX = (int) event.getRawX(); startY = (int) event.getRawY(); break; case MotionEvent.ACTION_MOVE

37、: endX = (int) event.getRawX(); endY = (int) event.getRawY(); /计算移动偏移量 dx = endX - startX; dy = endY - startY; /* *根据偏移量更新位置(重新部署位置) */ layoutParams.x += dx; layoutParams.y += dy; /更新位置 wm.updateViewLayout(ivDraw, layoutParams); /重新初始化坐标 startX = (int) event.getRawX(); startY = (int) event.getRawY()

38、; break; return true; ); /加载view wm.addView(ivDraw, layoutParams); 三.实现腾讯悬浮小火箭到这里,其实已经算是知道点逻辑了,我们就是用window去做的一个操作,既然如此,那我们就直接基于上面的代码去去实现这个小火箭吧,还是原来的代码,只是把图片更换成了一个小火箭,然后为了使它是是一个动态的效果,我们可以给他设置一个切换的动画<?xml version="1.0" encoding="utf-8"?><animation-list xmlns:android="

39、 > <item android:drawable="drawable/desktop_rocket_launch_in" android:duration="200"/> <item android:drawable="drawable/desktop_rocket_launch_out" android:duration="200"/></animation-list>这个其实就是两张图片的切换效果,我们直接去开启他 mView = View.inflate(getAp

40、plicationContext(), R.layout.rocket_window, null); ivRocket = (ImageView) mView.findViewById(R.id.ivRocket); AnimationDrawable anim = (AnimationDrawable) ivRocket.getBackground(); t();OK,现在我们去计算他的起飞了,而且还要考虑到他背景,我们其实可以大胆的使用一个Activity去做,我们在UP这个动作结束的时候就去计算坐标,当满足某一个坐标范围的时候就去启动动画和启动背景动画,那我们应该这样计算 case Mo

41、tionEvent.ACTION_UP: Log.i(TAG,"抬起"); Log.i(TAG,"抬起坐标:" + startX + ":" + startY); Log.i(TAG,"条件 : 200 < x >" + (width - 100) + "并且 y > " + (height - 200); /设置大致的发射范围 if (layoutParams.x > 50 && layoutParams.x < 250 && la

42、youtParams.y > 350) /发射火箭 sendRocket(); new Handler().postDelayed(new Runnable() Override public void run() /启动动画 Intent i = new Intent(getApplicationContext(), BackgroundActivity.class); i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(i); ,1000); break;这里其实偷了个懒,没有去做屏幕的严格适配,有兴趣的伙伴可以参考一下可

43、以看到我们有一个 sendRocket();方法就是启动小火箭,启动背景就是启动这个BackgroundActivity,我们先看小火箭 /* * 发射火箭的方法 */ private void sendRocket() new Thread(new Runnable() Override public void run() /动画 y坐标一直减少,实现上升动画 for (int i = 0; i <= height / 50; i+) /每循环一次减去乘以5 int y = height - i * 100; Log.i(TAG,"y = " + y); Messa

44、ge msg = new Message(); msg.arg1 = y; handler.sendMessage(msg); /暂停一下 try Thread.sleep(100); catch (InterruptedException e) e.printStackTrace(); ).start(); 因为要有节奏感,所以开了个handler来延迟一下,但是子线程不能更新主UI的,所以我们需要发一个handler来更新坐标private Handler handler = new Handler() Override public void handleMessage(Message

45、msg) super.handleMessage(msg); layoutParams.y = msg.arg1; /更新窗口 wm.updateViewLayout(mView, layoutParams); ;最后就是这个Activity了,里面真的啥也没有package com.lgl.viewandwindow;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.view.animation.AlphaAnimation;import android.widget.ImageView;/* * 烟雾动画 * Created by LGL on 2016/7/30. */public class BackgroundActivity extends Activity private ImageView smoke_m, smoke_t; Override protected void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); setContentView(R.layout.activ

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论