Activity和Window的View的移动的一些思考与体会腾讯悬浮小火箭的实现策略Word文件下载.docx
《Activity和Window的View的移动的一些思考与体会腾讯悬浮小火箭的实现策略Word文件下载.docx》由会员分享,可在线阅读,更多相关《Activity和Window的View的移动的一些思考与体会腾讯悬浮小火箭的实现策略Word文件下载.docx(33页珍藏版)》请在冰点文库上搜索。
match_parent"
layout_height="
gravity="
center"
orientation="
vertical"
padding="
10dp"
<
Button
id="
@+id/btnActivity"
wrap_content"
text="
Activity中View的移动"
textAllCaps="
false"
/>
@+id/btnWindow"
Window中View的移动"
@+id/btnTencent"
腾讯小火箭"
/LinearLayout>
不可否认,我们的MainActivty只是作为程序的入口,所以他的代码是十分的简单的
packagecom.lgl.viewandwindow;
importandroid.content.Intent;
importandroid.support.v7.app.AppCompatActivity;
importandroid.os.Bundle;
importandroid.view.View;
importandroid.widget.Button;
publicclassMainActivityextendsAppCompatActivityimplementsView.OnClickListener{
privateButtonbtnActivity,btnWindow,btnTencent;
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
//初始化View
privatevoidinitView(){
btnActivity=(Button)findViewById(R.id.btnActivity);
btnActivity.setOnClickListener(this);
btnWindow=(Button)findViewById(R.id.btnWindow);
btnWindow.setOnClickListener(this);
btnTencent=(Button)findViewById(R.id.btnTencent);
btnTencent.setOnClickListener(this);
//点击事件
publicvoidonClick(Viewv){
switch(v.getId()){
caseR.id.btnActivity:
startActivity(newIntent(this,ActivityActivity.class));
break;
caseR.id.btnWindow:
startActivity(newIntent(this,WindowActivity.class));
caseR.id.btnTencent:
startActivity(newIntent(this,TencentActivity.class));
}
而我们的重点也不在这里,而在这些子Activity
一.Activity中View的移动
实际上,View在Activity上移动,还是要依靠事件去传递,总所周知,View的绘制流程一般都是先onMeasure测量,接下来是onLayout确定位置,最后才是onDraw绘制,所以,我们的更新坐标其实是在onLayout进行的,好吧,说这些再多都不如代码来的实际一点,我们在Activity中写一个ImageView
ImageView
@+id/ivDraw"
src="
@mipmap/ic_launcher"
我们就是要对他下手了,是的,就在OnTouchListener中进行,OnTouchListener回调中有一个MotionEvent类,他封装了我们触摸事件的大部分动作,其中就包括三大将军
switch(event.getAction()){
//按下
caseMotionEvent.ACTION_DOWN:
//抬起
caseMotionEvent.ACTION_UP:
//移动
caseMotionEvent.ACTION_MOVE:
而我们如果单单只是移动这个View的话,其实是用不到抬起这个UP的动作的,我们要想实现这个View的移动,首先得知道这个View在哪里,所以我们需要先定义两个变量
//起点坐标
privateintstartX,startY;
而我们什么时候得到View的初始坐标呢?
肯定是在按下这个动作上获取
startX=(int)event.getRawX();
startY=(int)event.getRawY();
而这里,肯定就会有人问,这个getX和getRowX有什么区别,其实区别还是挺大的,前者是获取当前父容器的X坐标,后者是相对于整个屏幕的坐标,OK,获取到之后,我们应该干什么?
这个时候我们应该使用到MOVE这个动作了,你在拖动,我计算偏移量并且更新这个View的位置,来达到移动的视觉效果,那我们还得定义几个变量
首先是你的重点坐标,有始有终
//终点坐标
privateintendX,endY;
紧接着,会让终点坐标减去起点坐标,来计算这个偏移量,所以有了偏移量的变量
//偏移量
privateintdx,dy;
所以,我们MOVE的动作里计算公式应该是这样的
endX=(int)event.getRawX();
endY=(int)event.getRawY();
//计算移动偏移量
dx=endX-startX;
dy=endY-startY;
获取到你移动的偏移量,我们就可以拿到移动后的坐标了,还记得我们在绘制矩形的时候用到的那套公式吗
我们直接套用这套公式,其实就可以得到左上右下的坐标了
intleft=tvAddress.getLeft()+dx;
inttop=tvAddress.getTop()+dy;
intright=tvAddress.getRight()+dx;
intbottom=tvAddress.getBottom()+dy;
OK,这里,其实有点类似于测量,测量结束之后就可以确定位置了,就得用到我们的onLayout了
//重新部署位置
ivDraw.layout(left,top,right,bottom);
到这里,其实很多人就以为走完了的,其实更新完位置之后,你还要把初始位置给初始化一下,也就是赋值成你更新后的坐标点
//重新初始化坐标
startX=(int)event.getRawX();
startY=(int)event.getRawY();
对了。
记得returntrue,这里你会问,为什么是true,因为true代表我要消耗掉这个事件,你其他的就不要接收了,你不信的话可以设置一个点击事件看看有没有效果!
这里,我们就算大功告成了,如果你想记录这个坐标点,你就会用到UP了,不多说,我们运行看看效果
但是这里,还需要优化一下,比如,我移动到边上的时候直接就进去了,我们应该放置这个View超过屏幕,对吧,那我们应该怎么做?
我们首先先获取到整个屏幕的宽高
wm=(WindowManager)getSystemService(WINDOW_SERVICE);
width=wm.getDefaultDisplay().getWidth();
height=wm.getDefaultDisplay().getHeight();
这样,我们通过WindowManager就能直接拿到宽高了,然后我们在移动的时候可以这样做
//防止上下
if(top<
0||bottom>
height-20){
returntrue;
//防止左右
if(left<
0||right>
width){
这样,我们就可以直接看到效果了
这里的减去20是状态栏的,但是下面的虚拟按键倒是没有考虑进去,不过思路真的可行
好了,上面是步骤,我们就直接把代码全部贴出来吧
importandroid.view.MotionEvent;
importandroid.view.WindowManager;
importandroid.widget.ImageView;
/**
*CreatedbyLGLon2016/7/28.
*/
publicclassActivityActivityextendsAppCompatActivity{
privateImageViewivDraw;
//终点坐标
//偏移量
//窗口管理器
privateWindowManagerwm;
//屏幕宽高
privateintwidth,height;
setContentView(R.layout.activity_activity);
ivDraw=(ImageView)findViewById(R.id.ivDraw);
ivDraw.setOnTouchListener(newView.OnTouchListener(){
publicbooleanonTouch(Viewv,MotionEventevent){
/**
*根据偏移量更新位置(重新部署位置)
intleft=ivDraw.getLeft()+dx;
inttop=ivDraw.getTop()+dy;
intright=ivDraw.getRight()+dx;
intbottom=ivDraw.getBottom()+dy;
//防止上下
//防止左右
//重新初始化坐标
});
二.Window中View的移动
Activity上毕竟是有迹可循,那Window上呢?
其实窗体上逻辑是差不多的,唯一差的,就是那些函数的调用了,OK,我们进入WindowActivity中,先写个Button启动这个Window
@+id/showWindow"
ShowWindow"
他所对应的点击事件
showWindow=(Button)findViewById(R.id.showWindow);
showWindow.setOnClickListener(newView.OnClickListener(){
showMoveWindow();
而我们这个小节的重点就的照顾一下showMoveWindow()这个方法了,怎么实现一个Window不是今天的重点,而且也确实没什么可讲的,我就直接上代码了
wm=(WindowManager)getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
//布局参数
finalWindowManager.LayoutParamslayoutParams=newWindowManager.LayoutParams();
layoutParams.width=WindowManager.LayoutParams.WRAP_CONTENT;
layoutParams.height=WindowManager.LayoutParams.WRAP_CONTENT;
layoutParams.flags=WindowManager.LayoutParams.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=newImageView(this);
ivDraw.setBackgroundResource(R.mipmap.ic_launcher);
//加载view
wm.addView(ivDraw,layoutParams);
这段代码就能实现一个window了,我们可以看一下
我们需要权限哦
uses-permissionandroid:
name="
android.permission.SYSTEM_ALERT_WINDOW"
1
我们是直接new了一个ImageView的,但是不妨碍我们使用View的移动,我们直接实现它的触摸事件
//触摸事件
我这里暂时也只是实现了两个动作,因为作为演示我们的UP确实用不上,我们有了前车之鉴,我们直接定义我们需要的变量吧
//起始坐标
OK,老套路,在DOWN中,我们只是获取当前的坐标
但是移动的时候,获取的就不是左上右下了,而是他的x和y坐标,因为他是window,所以我们用到的是LayoutParams,更新位置也是使用的LayoutParams,他有一个updateViewLayout的方法
layoutParams.x+=dx;
layoutParams.y+=dy;
//更新位置
wm.updateViewLayout(ivDraw,layoutParams);
当然,最后returntrue;
我们试试
而因为他是window的改哪里,他并不需要去做一些超出边距的处理,很nice
把这部分代码也全部贴上来
importandroid.content.Context;
importandroid.graphics.PixelFormat;
publicclassWindowActivityextendsAppCompatActivity{
privateButtonshowWindow;
//图片
priv