View与ViewGroup
文章目录
- 1. `View`和`ViewGroup`的关系
- 2. 坐标获取
- 3. View的滑动
- 3.1 案例`layout()`
- 3.2 案例`offsetLeftAndRight & offsetTopAndBottom`
- 3.3 案例`LayoutParams(改变布局参数)`
- 3.4 动画
- 3.4.1 属性动画
- 组合动画 `AnimatorSet`
- `XML`中定制属性动画
- 3.5 `scrollTo`与`scollBy`
1. View
和ViewGroup
的关系
View
是Android
所有控件的基类,我们平常用的布局控件 LinearLayout
,它继承自 ViewGroup
,ViewGroup
可以理解为 View
的组合,它可以包含很多 View
以及ViewGroup
。如下图:
需要注意的是ViewGroup
也继承自View
。ViewGroup
派生了多种布局控件子类,比如LinearLayout
、RelativeLayout
等。
2. 坐标获取
getTop()
,获取View
自身顶边到其父布局顶边的距离;getLeft()
,获取View
自身左边到其父布局左边的距离。getRight()
,获取View
自身右边到其父布局左边的距离。getBottom()
,获取View
自身底边到其父布局顶边的距离。View
获取自身宽度:width = getRight() - getLeft();
。当然系统提供了getWidth()
来直接获取;View
获取自身高度:height=getBottom() - getTop();
。同样的系统提供了getHeight()
来直接获取;- 触控事件中,使用
getRawX()
和触控事件中,使用getRawX()
和getRawY()
方法获得的坐标也是
Android
坐标系的坐标。getRawY()
方法获得的坐标也是Android
坐标系的坐标。 - 在触摸事件中,使用
onTouchEvent(MotionEvent event)
方法来处理,MotionEvent
也提供了获取焦点坐标的各种方法。 getX()
:获取点击事件距离控件左边的距离,即视图坐标。getY()
:获取点击事件距离控件顶边的距离,即视图坐标。getRawX()
:获取点击事件距离整个屏幕左边的距离,即绝对坐标。getRawY()
:获取点击事件距离整个屏幕顶边的距离,即绝对坐标。
3. View的滑动
View
的滑动是Android
实现自定义控件的基础,同时在开发中我们也难免会遇到View
的滑动处理。其实不管是哪种滑动方式,其基本思想都是类似的:当点击事件传到View
时,系统记下触摸点的坐标,手指移动时系统记下移动后触摸的坐标并算出偏移量,并通过偏移量来修改View
的坐标。实现View
滑动有很多种方法,在这里主要讲解6种滑动方法,分别是layout()
、offsetLeftAndRight()
与
offsetTopAndBottom()
、LayoutParams
、动画、scollTo
与 scollBy
,以及Scroller
。
3.1 案例layout()
首先自定义View
,如:
package com.example.myapplication;import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;import androidx.annotation.Nullable;public class MyView extends View {private int lastX;private int lastY;public MyView(Context context) {super(context);}public MyView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);}public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}// 复写onTouchEvent,以使用坐标@Overridepublic boolean onTouchEvent(MotionEvent event) {// 获取手指坐标int x = (int)event.getX();int y = (int)event.getY();switch (event.getAction()){case MotionEvent.ACTION_DOWN:lastX = x;lastY = y;break;case MotionEvent.ACTION_MOVE:int offsetx = x - lastX;int offsety = y - lastY;// 使用layout方法来重新放置它的位置layout(getLeft()+offsetx, getTop()+offsety, getRight()+offsetx, getBottom()+offsety);break;}return true;}
}
然后,在主布局文件中使用即可,如:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical" android:layout_width="match_parent"android:layout_height="match_parent"><com.example.myapplication.MyViewandroid:id="@+id/myView"android:layout_width="50dp"android:layout_height="50dp"android:background="@color/colorPrimary"/>
</LinearLayout>
效果:
拖动可移动。
3.2 案例offsetLeftAndRight & offsetTopAndBottom
case MotionEvent.ACTION_MOVE:int offsetx = x - lastX;int offsety = y - lastY;// 使用offsetLeftAndRight & offsetTopAndBottomoffsetLeftAndRight(offsetx);offsetTopAndBottom(offsety);break;
3.3 案例LayoutParams(改变布局参数)
LayoutParams
主要保存了一个View
的布局参数,因此我们可以通过LayoutParams
来改变View
的布局参数从而达到改变View
位置的效果。
case MotionEvent.ACTION_MOVE:int offsetx = x - lastX;int offsety = y - lastY;// 使用LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();layoutParams.leftMargin = getLeft() + offsetx;layoutParams.topMargin = getTop() + offsety;setLayoutParams(layoutParams);break;
这里使用LinearLayout.LayoutParams
的原因是主文件我们使用的布局是LinearLayout
。如果父控件是RelativeLayout
,则要使用RelativeLayout.LayoutParams
。还可以使用ViewGroup.MarginLayoutParams
来实现:
case MotionEvent.ACTION_MOVE:int offsetx = x - lastX;int offsety = y - lastY;// 使用ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams();layoutParams.leftMargin = getLeft() + offsetx;layoutParams.topMargin = getTop() + offsety;setLayoutParams(layoutParams);break;
3.4 动画
可以使用动画来进行移动。
布局文件不变,然后删除自定义控件中的onTouchEvent
方法,在res
文件下新建anim
文件夹,在其下新建translate.xml
文件,内容如下:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" android:fillAfter="true"><translateandroid:duration="1000"android:fromXDelta="0"android:toXDelta="300"/>
</set>
属性android:fillAfter="true"
用于设置运动后停留在该位置。
在MainActivity.java
中设置关联,即:
public class MainActivity extends AppCompatActivity {private RecyclerView recyclerView;private MyAdapter adapter;private List<String> mList;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.recycleview);MyView myView = findViewById(R.id.myView);// 设置关联,加载定义的动画myView.setAnimation(AnimationUtils.loadAnimation(this, R.anim.translate));}
}
需要注意的是,View
动画并不能改变View
的位置参数。如果对一个Button
进行如上的平移动画操作,当Button
平移300
像素停留在当前位置时,我们点击这个Button
并不会触发点击事件,但在我们点击这个Button
的原始位置时却触发了点击事件。在Android 3.0
时出现的属性动画解决了上述问题:
public class MainActivity extends AppCompatActivity {private RecyclerView recyclerView;private MyAdapter adapter;private List<String> mList;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.recycleview);MyView myView = findViewById(R.id.myView);// 从0变化到300ObjectAnimator.ofFloat(myView, "translationX", 0, 300).setDuration(1000).start();}
}
关于属性动画,这里做一个简单的介绍
3.4.1 属性动画
Android
中动画分类:
- 帧动画
View
动画,它提供了AlphaAnimation
、RotateAnimation
、TranslateAnimation
、ScaleAnimation
这4
种动画方式,并提供了AnimationSet
动画集合来混合使用多种动画。但不具有交互性,即:当某个元素发生View
动画后,其响应事件的位置依然在动画进行前的地方,所以View
动画只能做普通的动画效果,要避免涉及交互操。但是它的优点也非常明显:效率比较高,使用也方便。
作。- 属性动画,由
Android 3.0
推出。Animator
框架中使用最多的就是AnimatorSet
和ObjectAnimator
配合:使用ObjectAnimator
进行更精细化的控制,控制一个对象和一个属性值,而使用多个ObjectAnimator
组合到AnimatorSet
形成一个动画。属性动画通过调用属性get
、set
方法来真实地控制一个View
的属性值,因此,强大的属性动画框架基本可以实现所有的动画效果。
创建一个 ObjectAnimator
只需通过其静态工厂类直接返还一个ObjectAnimator
对象。参数包括一个对象和对象的属性名字,但这个属性必须有get
和set
方法,其内部会通过Java
反射机制来调用set
方法修改对象的属性值。
下面就是一些常用的可以直接使用的属性动画的属性值。
translationX
和translationY
:用来沿着X轴或者Y轴进行平移。rotation
、rotationX
、rotationY
:用来围绕View的支点进行旋转。PrivotX
和PrivotY
:控制View
对象的支点位置,围绕这个支点进行旋转和缩放变换处理。默认该支点
位置就是View
对象的中心点。alpha
:透明度,默认是1
(不透明),0
代表完全透明。x
和y
:描述View
对象在其容器中的最终位置。
如果一个属性没有get
、set
方法,也可以通过自定义一个属性类或包装类来间接地给这个属性增加get
和set
方法。如:
自定义view
:
public class MyView extends View {private int lastX;private int lastY;public MyView(Context context) {super(context);}public MyView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);}public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}
}
对应布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><com.example.myapplication.MyViewandroid:layout_height="50dp"android:layout_width="50dp"android:id="@+id/myView"android:background="@color/colorPrimary"/></LinearLayout>
主文件:
public class MainActivity extends AppCompatActivity {private RecyclerView recyclerView;private MyAdapter adapter;private List<String> mList;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);MyView myView = findViewById(R.id.myView);PackageView packageView = new PackageView(myView);ObjectAnimator.ofInt(packageView, "width", 300).setDuration(1000).start();}// 包装类public class PackageView{private View view;PackageView(View view){Log.d("HELLO", "PackageView: "+Boolean.toString(view==null));this.view = view;}public int getWidth(){return view.getLayoutParams().width;}public void setWidth(int width){Log.d("HELLO", "setWidth: "+Boolean.toString(this.view==null));view.getLayoutParams().width = width;// 重新绘制Viewview.requestLayout();}}
}
最终效果,宽度缓慢扩充到300
组合动画 AnimatorSet
上面的ObjectAnimator
针对单个属性动画,往往动画比较复杂,不单单涉及一个属性。就需要使用组合动画。
AnimatorSet.Builder
中包括以下4
个方法。
after
(Animator anim
):将现有动画插入到传入的动画之后执行。after
(long delay
):将现有动画延迟指定毫秒后执行。before
(Animator anim
):将现有动画插入到传入的动画之前执行。with
(Animator anim
):将现有动画和传入的动画同时执行。
如:
public class MainActivity extends AppCompatActivity {private RecyclerView recyclerView;private MyAdapter adapter;private List<String> mList;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);MyView myView = findViewById(R.id.myView);ObjectAnimator animator1 = ObjectAnimator.ofFloat(myView, "translationX", 300);ObjectAnimator animator2 = ObjectAnimator.ofFloat(myView, "scaleX", 1.0f, 2.0f);AnimatorSet set = new AnimatorSet();set.setDuration(1000);set.play(animator1).after(animator2);set.start();}
}
和View
动画一样,属性动画也可以直接写在XML
中。
XML
中定制属性动画
前面提到了View
也可以指定XML
动画,但是其改变后点击事件还是在原来位置上,故而这里的XML
属性动画还是ObjectAnimator
版本。
同样的,在animator
中定义test.xml
文件,内容如下:
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="wrap_content"android:layout_height="wrap_content"android:duration="1000"android:propertyName="scaleX"android:valueFrom="1.0"android:valueTo="3.0"android:valueType="floatType">
</objectAnimator>
主文件:
public class MainActivity extends AppCompatActivity {private RecyclerView recyclerView;private MyAdapter adapter;private List<String> mList;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);MyView myView = findViewById(R.id.myView);myView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {Toast.makeText(MainActivity.this, "Hello", Toast.LENGTH_SHORT).show();}});Animator animator = AnimatorInflater.loadAnimator(this, R.animator.test);animator.setTarget(myView);animator.start();}
}
3.5 scrollTo
与scollBy
scrollTo(x,y)
表示移动到一个具体的坐标点,而scrollBy(dx,dy)
则表示移动的增量为dx
、dy
。
case MotionEvent.ACTION_MOVE:int offsetx = x - lastX;int offsety = y - lastY;// 使用((View)getParent()).scrollBy(-offsetx, -offsety);break;
内容参考:
- 《Android进阶之光》
View与ViewGroup相关推荐
- Android精通:View与ViewGroup,LinearLayout线性布局,RelativeLayout相对布局,ListView列表组件...
UI的描述 对于Android应用程序中,所有用户界面元素都是由View和ViewGroup对象构建的.View是绘制在屏幕上能与用户进行交互的一个对象.而对于ViewGroup来说,则是一个用于存放 ...
- 【Android 应用开发】自定义View 和 ViewGroup
一. 自定义View介绍 自定义View时, 继承View基类, 并实现其中的一些方法. (1) ~ (2) 方法与构造相关 (3) ~ (5) 方法与组件大小位置相关 (6) ~ (9) 方法与触摸 ...
- View和ViewGroup常用方法
2019独角兽企业重金招聘Python工程师标准>>> Android的UI界面都是由View和ViewGroup及其派生类组合而成的. 其中,View是所有UI组件的基类,而 Vi ...
- 精通android布局,Android精通:View与ViewGroup,LinearLayout线性布局,RelativeLayout相对布局,ListView列表组件...
标题图 UI的描述 对于Android应用程序中,所有用户界面元素都是由View和ViewGroup对象构建的.View是绘制在屏幕上能与用户进行交互的一个对象.而对于ViewGroup来说,则是一个 ...
- Android(四)——View和ViewGroup
文章目录 1. 用户界面概述 2. View类常用属性 3. ViewGroup类 4. UI组件的层次结构 1. 用户界面概述 在Android APP中,所有的用户界面元素都是由View和View ...
- View和ViewGroup的层次关系
Layout也是一种View Widget - View Layout - ViewGroup
- android应用的界面编程----View与ViewGroup的概念
1 UI OverView Android中所有的UI元素都是通过View与ViewGroup来构建的,View是指屏幕中一块可与用户进行交互的空白,类似于java界面编程中的JPanel.为了界面布 ...
- Android 应用开发(35)---View与ViewGroup的概念
View与ViewGroup的概念 告别了第一章,迎来第二章--Android中的UI(User Interface)组件的详解, 而本节我们要学习的是所有控件的父类View和ViewGroup类!突 ...
- 【Android】Android自定义View和ViewGroup知识点汇总
一.View的绘制流程 onMeasure()->onDraw(). 二.ViewGroup的绘制流程 onMeasure()->onLayout()->onDraw()(一般不重写 ...
最新文章
- CYQ.Data V4系列全面开源(2013-08-04)
- 如果产品经理去卖土豆粉
- 关于memcached
- 软件质量保证计划_如何做好软件项目的质量管理?
- java中int,char,string三种类型的相互转换
- cocos2dx[3.2](11)——新回调函数std::bind
- python 进位_蓝桥杯-Python-高精度加法
- mtk camera faq
- python自动语音电话_用 Python 实现自己的智能语音助理(百度语音 + 图灵机器人)...
- excel饼图按占比从大到小排列
- android——java.lang.IllegalStateException: Fatal Exception thrown on Scheduler
- 国家也补贴?有华为认证证书的你,就能拿它(附详细操作)
- 每日一言:愿你等待的,终有回答
- 安卓手机使用Termux软件进行Linux系统的安装
- 裴波那契数列(循环实现递归)
- 默克高性能材料业务正式更名为“电子科技(Electronics)”
- 山野村夫的总提纲!……还是羞于见人啦=////=
- 机械键盘Windows键失灵,解决办法
- 免疫算法求解多元函数论文
- 采集程序 -【开源项目】