Activity和Window的View的移動的一些思考與體會,騰訊懸浮小火箭的實現(xiàn)策略_第1頁
Activity和Window的View的移動的一些思考與體會,騰訊懸浮小火箭的實現(xiàn)策略_第2頁
Activity和Window的View的移動的一些思考與體會,騰訊懸浮小火箭的實現(xiàn)策略_第3頁
Activity和Window的View的移動的一些思考與體會,騰訊懸浮小火箭的實現(xiàn)策略_第4頁
Activity和Window的View的移動的一些思考與體會,騰訊懸浮小火箭的實現(xiàn)策略_第5頁
已閱讀5頁,還剩19頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、Activity和Window的View的移動的一些思考與體會,騰訊懸浮小火箭的實現(xiàn)策略事實上寫這個也是因為自己實際在項目中用到了才會去研究已經寫文章,對于View的移動,其實說實話,已經有很多文章了,既然如此的話,那我實在是不好意思再去重復的講解,但是和Window的View還是有一些區(qū)別的,接下來,我會實際的講解一下這些區(qū)別已經坐標函數(shù)的計算方法,當然,最后再講一下如何實現(xiàn)騰訊的懸浮小火箭,這些都是比較好的干貨,我也相信大家都是比較喜歡的,而你在本文中將學會使用View的移動計算坐標,有三個目錄1.Activity中View的移動2.Window中View的移動3.實現(xiàn)騰訊懸浮小火箭我們首

2、先新建一個項目ViewAndWindow來實現(xiàn)三個按鈕作為這三個功能的三個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的動作的,我們要想實現(xiàn)這個View的移動,首先得知道這個View在哪里,所以我們需要先定義兩個變量 /起點坐標 private i

12、nt startX, startY;而我們什么時候得到View的初始坐標呢?肯定是在按下這個動作上獲取 startX = (int) event.getRawX(); startY = (int) event.getRawY();而這里,肯定就會有人問,這個getX和getRowX有什么區(qū)別,其實區(qū)別還是挺大的,前者是獲取當前父容器的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了,不多說,我們運行看看效果但是這里,還需要優(yōu)化一下,比如,我移動到邊上的時候直接就進去了,我們應該放置這個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是狀態(tài)欄的,但是下面的虛擬按鍵倒是沒有

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; /* *根據(jù)偏移量更新位置(重新部署位置) */ 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上呢?其實窗體上邏輯是差不多的,唯一差的,就是那些函數(shù)的調用了,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(); );而我們這個小節(jié)的重點就的照顧一下 showMoveWindow()這個方法了,怎么實現(xiàn)一個Window不是今天的重點,而且也確實沒什么可講的,我就直接上代碼了 /窗口管理器 wm = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE); /

25、布局參數(shù) 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);這段代碼就能實現(xiàn)一個window了,我們可以看一下我們需要權限哦<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />11我們是直接new了一個ImageView的,但是不妨礙我們使用View的移動,我們直接實現(xiàn)它的觸摸事件 /觸摸事件 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; );我這里暫時也只是實現(xiàn)了兩個動作,因為作為演示我們的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; /* *根據(jù)偏移量更新位置(重新部署位置)

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); /布局參數(shù) 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; /* *根據(jù)偏移量更新位置(重新部署位置) */ 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); 三.實現(xiàn)騰訊懸浮小火箭到這里,其實已經算是知道點邏輯了,我們就是用window去做的一個操作,既然如此,那我們就直接基于上面的代碼去去實現(xiàn)這個小火箭吧,還是原來的代碼,只是把圖片更換成了一個小火箭,然后為了使它是是一個動態(tài)的效果,我們可以給他設置一個切換的動畫<?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,現(xiàn)在我們去計算他的起飛了,而且還要考慮到他背景,我們其實可以大膽的使用一個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); /設置大致的發(fā)射范圍 if (layoutParams.x > 50 && layoutParams.x < 250 && la

42、youtParams.y > 350) /發(fā)射火箭 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,我們先看小火箭 /* * 發(fā)射火箭的方法 */ private void sendRocket() new Thread(new Runnable() Override public void run() /動畫 y坐標一直減少,實現(xiàn)上升動畫 for (int i = 0; i <= height / 50; i+) /每循環(huán)一次減去乘以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(); 因為要有節(jié)奏感,所以開了個handler來延遲一下,但是子線程不能更新主UI的,所以我們需要發(fā)一個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. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論