一、View
Android 应用中的所有用户界面元素都是使用 View 和 ViewGroup 对象构建而成。View 对象用于在屏幕上绘制可供用户交互的内容。ViewGroup 对象用于储存其他 View(和 ViewGroup)对象,以便定义界面的布局。
Android 提供了一系列 View 和 ViewGroup 子类,可为您提供常用输入控件(如按钮和文本字段)和各种布局模式(如线性布局或相对布局)。
当然,ViewGroup也是View,View是Android中所有控件的基类。
二、Android坐标系
View的位置是由它的四个顶点决定,对应它的四个属性:Left、Top、Right、Bottom
- Left = getLeft();
- Top = getTop();
- Right = getRight();
- Bottom = getBottom();
3.0后,view增加了新的几个参数:x、y、translationX、translationY;x、y是view的左上角坐标,translationX、translationY是View相对于它的getLeft()、getRight(),也就是它的初始位置的偏移量
- x = getX();
- y = getY();
- translationX = getTranslationX();
- translationY = getTranslationY();
Left、Top、Right、Bottom四个参数在View的平移过程中不会改变,变的是新增的几个参数,关系如下:
- x = left + translationX;
- y = top + translationY;
// View源码
public float getX() {
return mLeft + getTranslationX();
}
public float getY() {
return mTop + getTranslationY();
}
三、View的滑动
三、Android中的角度和弧度
数学中的角度制(Degree Measure)
把一个圆周平均分成360份,其中的每一份都是1°的角。这种以“度”作为单位来度量角度单位制叫做角度制。下图是我们常见的180°角度尺。
数学中的弧度制(Radian Measure)
长度为半径长的弧,所对的圆心角是1弧度(Radian),用符号rad表示。
角度和弧度换算
360° = 2π rad
180° = π rad
1° =(π / 180)rad ≈ 0.01745 rad
1 rad =(180 /π)° ≈ 57.30°
α 度的角 = α ·(π / 180)rad
Android中弧度增大的方向:
四、Android中的颜色
颜色模式
颜色定义
1.代码定义
int color = Color.GRAY; // 灰色
// Color类是使用ARGB值进行表示
int color = Color.argb(127, 255, 0, 0); // 半透明红色
int color = 0xaaff0000; // 带有透明度的红色
2.xml定义
// 定义了红色(没有alpha(透明)通道)
<color name="red">#ff0000</color>
// 定义了蓝色(没有alpha(透明)通道)
<color name="green">#00ff00</color>
颜色引用
1.java代码引用
int color = getResources().getColor(R.color.red);
2.xml引用
<!--在layout文件中引用在/res/values/color.xml中定义的颜色-->
android:background="@color/red"
<!--在layout文件中创建并使用颜色-->
android:background="#ff0000"
五、 自定义View常用类
1. MotionEvent :触摸事件
典型的事件类型:
- ACTION_DOWN : 手指刚接触到屏幕
- ACTION_UP : 手指从屏幕上抬起时
- ACTION_MOVE : 手指在屏幕上移动
我们可以通过MotionEvent得到事件发生的坐标位置:
- getX() : 相对于当前view左上角的x坐标
- getY() : 相对于当前view左上角的y坐标
- getRawX() : 相对于手机屏幕左上角的x坐标
- getRawY() : 相对于手机屏幕左上角的y坐标
可以参照上面的图
2. Configuration :设备配置信息相关
// ----------- Configuration 设备配置信息相关类
Configuration configuration = getResources().getConfiguration();
// 国家码 310
int mcc = configuration.mcc;
// 网络码 260
int mnc = configuration.mnc;
// 横竖屏 1 ORIENTATION_PORTRAIT 2 ORIENTATION_LANDSCAPE,
int orientation = configuration.orientation;
3. ViewConfiguration:UI中超时、大小、距离相关
// ------------ ViewConfiguration UI中超时、大小、距离相关
ViewConfiguration viewConfiguration = ViewConfiguration.get(this);
// 系统可识别最小滑动距离 16
int touchSlop = viewConfiguration.getScaledTouchSlop();
// 是否有物理按键 false
boolean isHasPermanentMenuKey = viewConfiguration.hasPermanentMenuKey();
// 静态方法 有效的双击间隔时间 300
int doubleTapTimeout = ViewConfiguration.getDoubleTapTimeout();
// 静态方法 按住变为长按需要的时间 500
int longPressTimeout = ViewConfiguration.getLongPressTimeout();
4. GestureDetector :手势处理工具
当用户触摸屏幕会产生很多手势,我们可以通过View的onTounchEvent()来判断各种手势,但太过麻烦;系统为我们提供了GestureDetector这个类,其中的onTouchEvent(MotionEvent ev)方法替我们判断了各种手势,然后我们再根据它提供的几种接口,只专注于每种手势后续的处理。
其中包括三个接口和一个实现了三个接口的类(空实现):
- OnGestureListener
- onSingleTapUp : 点击抬起回调,不能代表是单击事件
- onLongPress :长按回调,回调后不会再触发其他时间
- onScroll : 手指滑动时回调
- onFling : 快速滑动到一定速度松开后继续滑动回调
- onShowPress : 按住屏幕未移动也未松开时调用,用于告诉用户已经识别按下事件的回调
- onDown : 按下屏幕时回调
- OnDoubleTapListener
- onDoubleTap : 确认是双击事件回调
- onDoubleTapEvent : 双击后的其他事件回调
- onSingleTapConfirmed : 确认是单击事件回调
- OnContextClickListener
- onContextClick : 鼠标、触摸板,右键点击时回调
- SimpleOnGestureListener : 实现了以上三个接口
我们可以根据不同的需求实现不同的接口,如果还是觉得需要实现的方法太多,可以继承SimpleOnGestureListener类,选择需要的方法实现
使用如下:
1.创建OnGestureListener的实现类
/**
* 1. 创建OnGestureListener的实现类
*/
class MyGestureDetectorListener extends GestureDetector.SimpleOnGestureListener{
// ---------- OnGestureListener 部分
@Override
public boolean onSingleTapUp(MotionEvent e) {
Log.e(TAG,"onSingleTapUp============");
return super.onSingleTapUp(e);
}
@Override
public void onLongPress(MotionEvent e) {
Log.e(TAG,"onLongPress============");
super.onLongPress(e);
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
Log.e(TAG,"onScroll============");
return super.onScroll(e1, e2, distanceX, distanceY);
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
Log.e(TAG,"onFling============");
return super.onFling(e1, e2, velocityX, velocityY);
}
@Override
public void onShowPress(MotionEvent e) {
Log.e(TAG,"onShowPress============");
super.onShowPress(e);
}
@Override
public boolean onDown(MotionEvent e) {
Log.e(TAG,"onDown============");
return super.onDown(e);
}
// ----------- OnDoubleTapListener 部分
@Override
public boolean onDoubleTap(MotionEvent e) {
Log.e(TAG,"onDoubleTap============");
return super.onDoubleTap(e);
}
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
Log.e(TAG,"onDoubleTapEvent============");
return super.onDoubleTapEvent(e);
}
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
Log.e(TAG,"onSingleTapConfirmed============");
return super.onSingleTapConfirmed(e);
}
// -------------- OnContextClickListener 部分
@Override
public boolean onContextClick(MotionEvent e) {
Log.e(TAG,"onContextClick============");
return super.onContextClick(e);
}
}
2.创建GestureDetector
// 2. 创建GestureDetector
GestureDetector gestureDetector = new GestureDetector(this,new MyGestureDetectorListener());
3.将TounchEvent交给GestureDetector处理
mButton.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// 3. 将TounchEvent交给GestureDetector处理
return gestureDetector.onTouchEvent(event);
}
});
《Android开发艺术探索》中建议:如果只是监听滑动相关,建议自己在onTounch中实现;如果是监听单击双击行为,就使用GestureDetector
5. VelocityTracker : 速度跟踪
跟踪触摸事件的速度,用于实现fling或类似的效果
大概使用如下,具体项目中没使用过:
mButton.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
// 1. 创建VelocityTracker,添加追踪事件
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
break;
case MotionEvent.ACTION_MOVE:
// 2. 添加要追踪的事件
mVelocityTracker.addMovement(event);
// 3. 计算1s内的速度
mVelocityTracker.computeCurrentVelocity(1000);
float x = mVelocityTracker.getXVelocity();
float y = mVelocityTracker.getYVelocity();
Log.e("VelocityTracker", " x:"+x+" y:"+y );
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
// 4. 重置回收
mVelocityTracker.clear();
mVelocityTracker.recycle();
mVelocityTracker = null;
break;
}
return false;
}
});
6. Scroller :弹性滑动
弹性滑动对象,用于view实现弹性滑动。scrollTo()和scrollBy()是瞬间完成滑动,而使用Scroller是在一个时间段完成滑动。
Scroller本身也无法完成View的滑动,它需要和View的computeScroll()方法配合才行。
Scroller、scrollTo()、scrollBy()都是滑动View自身的内容。
Scroller的使用代码基本是固定的,如下:
/**
* 可滑动内容的LinearLayout
* @author StriveStay
* @date 2018/3/15
*/
public class ScrollLinearLayout extends LinearLayout {
private Scroller mScroller;
public ScrollLinearLayout(Context context) {
this(context,null);
}
public ScrollLinearLayout(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public ScrollLinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// 1. 创建Scroller
mScroller = new Scroller(context);
}
/**
* 滚动
* @param destX x轴滚动距离,负数:内容向x轴正方向移动;正数:内容向X轴负方向移动
* @param destY y轴滚动距离,负数:内容向Y轴正方向移动;正数:内容向Y轴负方向移动
*/
public void smoothScrollTo(int destX,int destY){
// 2. 指定滚动的开始位置,x,y轴上的滚动距离,滚动时间,开始滚动
mScroller.startScroll(60,60,destX,destY,3000);
// 3. 调用此方法会重绘,draw()中会调用computeScroll()方法
invalidate();
}
// 4. 重写该方法(用于在其中计算在开始滚动后的持续时间内,该时间点应该滚动的距离)
@Override
public void computeScroll() {
super.computeScroll();
// getScrollX() View内容相对于View左边缘在X轴的位置,负数:内容向x轴正方向移动;正数:内容向X轴负方向移动
// getScrollY() View内容相对于View上边缘在Y轴的位置,负数:内容向Y轴正方向移动;正数:内容向Y轴负方向移动
Log.e("Scroller计算前","getScrollX:"+getScrollX()+" getScrollY:"+getScrollY()
+" getCurrX:"+mScroller.getCurrX()+" getCurrY:"+mScroller.getCurrY());
// 5. 计算该时间点应该滚动到的位置,并判断滑动是否完成,ture是未完成
if(mScroller.computeScrollOffset()){
Log.e("Scroller计算后","getScrollX:"+getScrollX()+" getScrollY:"+getScrollY()
+" getCurrX:"+mScroller.getCurrX()+" getCurrY:"+mScroller.getCurrY());
// 6. 调用scrollTo(),滚动到计算出的指定位置,会先滚动到第2步中的开始位置
scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
// 7. 重绘,继续调用computeScroll()方法,形成循环,直到滚动结束
invalidate();
}
}
}
mScrollLinearLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 8. 调用滚动方法
mScrollLinearLayout.smoothScrollTo(-300,0);
}
});
效果:
我的理解:
7. ViewDragHelper :自定义 ViewGroup 拖拽辅助类
1. Android ViewDragHelper完全解析 自定义ViewGroup神器
2. ViewDragHelper实战 自己打造Drawerlayout
鸿洋大神总结的两篇文章,很好
8. DisplayMetrics :屏幕信息相关
// 第一种方式
// DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
// 第二种方式
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
// 屏幕密度
float density = metrics.density;
// 屏幕密度,以每英寸的像素点数表示
int densityDpi = metrics.densityDpi;
// 屏幕宽度
int widthPixels = metrics.widthPixels;
// 屏幕高度
int heightPixels = metrics.heightPixels;