setPadding(int, int, int, int) 这个就可以控制边距了
各种Layout用到的一些重要的属性:
第一类:属性值为true或false
android:layout_centerHrizontal 水平居中
android:layout_centerVertical 垂直居中
android:layout_centerInparent 相对于父元素完全居中
android:layout_alignParentBottom 贴紧父元素的下边缘
android:layout_alignParentLeft 贴紧父元素的左边缘
android:layout_alignParentRight 贴紧父元素的右边缘
android:layout_alignParentTop 贴紧父元素的上边缘
android:layout_alignWithParentIfMissing 如果对应的兄弟元素找不到的话就以父元素做参照物
第二类:属性值必须为id的引用名“@id/id-name”
android:layout_below 在某元素的下方
android:layout_above 在某元素的的上方
android:layout_toLeftOf 在某元素的左边
android:layout_toRightOf 在某元素的右边
android:layout_alignTop 本元素的上边缘和某元素的的上边缘对齐
android:layout_alignLeft 本元素的左边缘和某元素的的左边缘对齐
android:layout_alignBottom 本元素的下边缘和某元素的的下边缘对齐
android:layout_alignRight 本元素的右边缘和某元素的的右边缘对齐
第三类:属性值为具体的像素值,如30dip,40px
android:layout_marginBottom 离某元素底边缘的距离
android:layout_marginLeft 离某元素左边缘的距离
android:layout_marginRight 离某元素右边缘的距离
android:layout_marginTop 离某元素上边缘的距离
EditText的android:hint
设置EditText为空时输入框内的提示信息。
android:gravity
android:gravity属性是对该view 内容的限定比如一个button 上面的text 你可以设置该text 在view的靠左,靠右等位置以button为例,android:gravity=”right”则button上面的文字靠右
android:layout_gravity
android:layout_gravity是用来设置该view相对与起父view 的位置比如一个button 在linearlayout里,你想把该button放在靠左、靠右等位置就可以通过该属性设置以button为例,android:layout_gravity=”right”则button靠右
android:layout_alignParentRight
使当前控件的右端和父控件的右端对齐。这里属性值只能为true或false,默认false。
android:scaleType:
android:scaleType是控制如何resized/moved来匹对ImageView的size。ImageViewScaleType / android:scaleType值的意义区别:
CENTER /center 按的原来size居中显示,当长/宽超过View的长/宽,则截取的居中部分显示
CENTER_CROP / centerCrop 按比例扩大的size居中显示,使得长(宽)等于或大于View的长(宽)
CENTER_INSIDE / centerInside 将的内容完整居中显示,通过按比例缩小或原来的size使得长/宽等于或小于View的长/宽
FIT_CENTER / fitCenter 把按比例扩大/缩小到View的宽度,居中显示
FIT_END / fitEnd 把按比例扩大/缩小到View的宽度,显示在View的下部分位置
FIT_START / fitStart 把按比例扩大/缩小到View的宽度,显示在View的上部分位置
FIT_XY / fitXY 把不按比例扩大/缩小到View的大小显示
MATRIX / matrix用矩阵来绘制,动态缩小放大来显示。
XML属性
属性名称
描述
android:background
设置背景色/背景。可以通过以下两种方法设置背景为透明:”@android:color /transparent”和”@null”。注意TextView默认是透明的,不用写此属性,但是Buttom/ImageButton /ImageView想透明的话就得写这个属性了。
android:clickable
是否响应点击事件。
android:contentDescription
设置View的备注说明,作为一种辅助功能提供,为一些没有文字描述的View提供说明,如ImageButton。这里在界面上不会有效果,自己在程序中控制,可临时放一点字符串数据。
android:drawingCacheQuality
设置绘图时半透明质量。有以下值可设置:auto(默认,由框架决定)/high(高质量,使用较高的颜色深度,消耗更多的内存)/low(低质量,使用较低的颜色深度,但是用更少的内存)。
android:duplicateParentState
如果设置此属性,将直接从父容器中获取绘图状态(光标,按下等)。 见下面代码部分,注意根据目前测试情况仅仅是获取绘图状态,而没有获取事件,也就是你点一下LinearLayout时Button有被点击的效果,但是不执行点击事件。
android:fadingEdge
设置拉滚动条时 ,边框渐变的放向。none(边框颜色不变),horizontal(水平方向颜色变淡),vertical(垂直方向颜色变淡)。参照fadingEdgeLength的效果图
android:fadingEdgeLength
设置 边框渐变的长度。
android:fitsSystemWindows
设置布局调整时是否考虑系统窗口(如状态栏)
android:focusable
设置是否获得焦点。若有requestFocus()被调用时,后者优先处理。注意在表单中想设置某一个如 EditText获取焦点,光设置这个是不行的,需要将这个EditText前面的focusable都设置为false才行。在Touch模式下获取焦点需要设置focusableInTouchMode为true。
android:focusableInTouchMode
设置在Touch模式下View是否能取得焦点。
android:hapticFeedbackEnabled
设置长按时是否接受其他触摸反馈事件。这里模拟器没有试出效果,难道是多点触摸?找不到资料可以找找performHapticFeedback或HapticFeedback这个关键字的资料看看。
android:id
给当前View设置一个在当前layoutxml中的唯一编号,可以通过调用ViewfindViewById() 或ActivityfindViewById()根据这个编号查找到对应的View。不同的layoutxml之间定义相同的id不会冲突。格式如”@+id/btnName”
android:isScrollContainer
设置当前View为滚动容器。这里没有测试出效果来,ListView/ GridView/ ScrollView根本就不用设置这个属性,而EdidText设置android:scrollbars也能出滚动条。
android:keepScreenOn
View在可见的情况下是否保持唤醒状态。
常在LinearLayout使用该属性,但是模拟器这里没有效果。
android:longClickable
设置是否响应长按事件
android:minHeight
设置视图最小高度
android:minWidth
设置视图最小宽度度
android:nextFocusDown
设置下方指定视图获得下一个焦点。焦点移动是基于一个在给定方向查找最近邻居的算法。如果指定视图不存在,移动焦点时将报运行时错误。可以设置imeOptions= actionDone,这样输入完即跳到下一个焦点。
android:nextFocusLeft
设置左边指定视图获得下一个焦点。
android:nextFocusRight
设置右边指定视图获得下一个焦点。
android:nextFocusUp
设置上方指定视图获得下一个焦点。
android:onClick
点击时从上下文中调用指定的方法。这里指定一个方法名称,一般在Activity定义符合如下参数和返回值的函数并将方法名字符串指定为该值即可:
public void onClickButton(View view)
android:onClick=” onClickButton”
android:padding
设置上下左右的边距,以像素为单位填充空白。
android:paddingBottom
设置底部的边距,以像素为单位填充空白。
android:paddingLeft
设置左边的边距,以像素为单位填充空白。
android:paddingRight
设置右边的边距,以像素为单位填充空白。
android:paddingTop
设置上方的边距,以像素为单位填充空白。
android:saveEnabled
设置是否在窗口冻结时(如旋转屏幕)保存View的数据,默认为true,但是前提是你需要设置id才能自动保存,参见这里。
android:scrollX
以像素为单位设置水平方向滚动的的偏移值,在GridView中可看的这个效果。
android:scrollY
以像素为单位设置垂直方向滚动的的偏移值
android:scrollbarAlwaysDrawHorizontalTrack
设置是否始终显示垂直滚动条。这里用ScrollView、ListView测试均没有效果。
android:scrollbarAlwaysDrawVerticalTrack
设置是否始终显示垂直滚动条。这里用ScrollView、ListView测试均没有效果。
android:scrollbarDefaultDelayBeforeFade
设置N毫秒后开始淡化,以毫秒为单位。
android:scrollbarFadeDuration
设置滚动条淡出效果(从有到慢慢的变淡直至消失)时间,以毫秒为单位。Android22中滚动条滚动完之后会消失,再滚动又会出来,在15、16版本里面会一直显示着。
android:scrollbarSize
设置滚动条的宽度。
android:scrollbarStyle
设置滚动条的风格和位置。设置值:insideOverlay、insideInset、outsideOverlay、outsideInset。这里没有试出太多效果,以下依次是outsideOverlay与outsideInset效果截图比较:
android:scrollbarThumbHorizontal
设置水平滚动条的drawable(如颜色)。
android:scrollbarThumbVertical
设置垂直滚动条的drawable(如颜色)
android:scrollbarTrackHorizontal
设置水平滚动条背景(轨迹)的色drawable(如颜色)
android:scrollbarTrackVertical
设置垂直滚动条背景(轨迹)的drawable注意直接设置颜色值如”android:color/white”将得出很难看的效果,甚至都不理解这个属性了,这里可以参见ApiDemos里res/drawable/ scrollbar_vertical_thumbxml和scrollbar_vertical_trackxml,设置代码为:android:scrollbarTrackVertical ="@drawable/scrollbar_vertical_track"
android:scrollbars
设置滚动条显示。none(隐藏),horizontal(水平),vertical(垂直)。见下列代码演示使用该属性让EditText内有滚动条。但是其他容器如LinearLayout设置了但是没有效果。
android:soundEffectsEnabled
设置点击或触摸时是否有声音效果
android:tag
设置一个文本标签。可以通过ViewgetTag()或 for with ViewfindViewWithTag()检索含有该标签字符串的View。但一般最好通过ID来查询View,因为它的速度更快,并且允许编译时类型检查。
android:visibility
设置是否显示View。设置值:visible(默认值,显示),invisible(不显示,但是仍然占用空间),gone(不显示,不占用空间)
XML属性
属性名称描述
android:background 设置背景色/背景。可以通过以下两种方法设置背景为透明:”@android:color/transparent”和”@null”。注意 TextView 默认是透明的,不用写此属性,但是Buttom/ImageButton/ImageView想透明的话就得写这个属性了。
android:clickable 是否响应点击事件。
android:contentDescription 设置View的备注说明,作为一种辅助功能提供,为一些没有文字描述的View提供说明,如ImageButton。这里在界面上 不会有效果,自己在程序中控制,可临时放一点字符串数据。
android:drawingCacheQuality 设置绘图时半透明质量。有以下值可设置:auto(默认,由框架决定)/high(高质量,使用较高的颜色深度,消耗更多的内存)/low(低质量,使用较低的颜色深度,但是用更少的内存)。
android:duplicateParentState 如果设置此属性,将直接从父容器中获取绘图状态(光标,按下等)。见下面代码部分,注意根据目前测试情况仅仅是获取绘图状态,而没有获取事件,也就是你点一下LinearLayout时Button有被点击的效果,但是不执行点击事件。
android:fadingEdge 设置拉滚动条时,边框渐变的放向。none(边框颜色不变),horizontal(水平方向颜色变淡),vertical(垂直方向颜色变淡)。参照fadingEdgeLength的效果图
android:fadingEdgeLength 设置边框渐变的长度。
android:fitsSystemWindows 设置布局调整时是否考虑系统窗口(如状态栏)
android:focusable 设置是否获得焦点。若有requestFocus()被调用时,后者优先处理。注意在表单中想设置某一个如EditText获取焦点,光设置这个是不行的,需要将这个EditText前面的focusable都设置为false才行。在Touch模式下获取焦点需要设置 focusableInTouchMode为true。
android:focusableInTouchMode 设置在Touch模式下View是否能取得焦点。
android:hapticFeedbackEnabled 设置长按时是否接受其他触摸反馈事件。这里模拟器没有试出效果,难道是多点触摸?找不到资料可以找找performHapticFeedback或HapticFeedback这个关键字的资料看看。
android:id 给当前View设置一个在当前layoutxml中的唯一编号,可以通过调用ViewfindViewById() 或ActivityfindViewById()根据这个编号查找到对应的View。不同的layoutxml之间定义相同的id不会冲突。格式如”@+id/btnName”
android:isScrollContainer 设置当前View为滚动容器。这里没有测试出效果来,ListView/ GridView/ ScrollView根本就不用设置这个属性,而EdidText设置android:scrollbars也能出滚动条。
android:keepScreenOn View在可见的情况下是否保持唤醒状态。
常在LinearLayout使用该属性,但是模拟器这里没有效果。
android:longClickable 设置是否响应长按事件
android:minHeight 设置视图最小高度
android:minWidth 设置视图最小宽度度
android:nextFocusDown 设置下方指定视图获得下一个焦点。焦点移动是基于一个在给定方向查找最近邻居的算法。如果指定视图不存在,移动焦点时将报运行时错误。可以设置imeOptions= actionDone,这样输入完即跳到下一个焦点。
android:nextFocusLeft 设置左边指定视图获得下一个焦点。
android:nextFocusRight 设置右边指定视图获得下一个焦点。
android:nextFocusUp 设置上方指定视图获得下一个焦点。
android:onClick 点击时从上下文中调用指定的方法。这里指定一个方法名称,一般在Activity定义符合如下参数和返回值的函数并将方法名字符串指定为该值即可:
public voidonClickButton(View view)
android:onClick=”onClickButton”
android:padding 设置上下左右的边距,以像素为单位填充空白。
android:paddingBottom 设置底部的边距,以像素为单位填充空白。
android:paddingLeft 设置左边的边距,以像素为单位填充空白。
android:paddingRight 设置右边的边距,以像素为单位填充空白。
android:paddingTop 设置上方的边距,以像素为单位填充空白。
android:saveEnabled 设置是否在窗口冻结时(如旋转屏幕)保存View的数据,默认为true,但是前提是你需要设置id才能自动保存,参见这里。
android:scrollX 以像素为单位设置水平方向滚动的的偏移值,在GridView中可看的这个效果。
android:scrollY 以像素为单位设置垂直方向滚动的的偏移值
android:scrollbarAlwaysDrawHorizontalTrack 设置是否始终显示垂直滚动条。这里用ScrollView、ListView测试均没有效果。
android:scrollbarAlwaysDrawVerticalTrack 设置是否始终显示垂直滚动条。这里用ScrollView、ListView测试均没有效果。
android:scrollbarDefaultDelayBeforeFade 设置N毫秒后开始淡化,以毫秒为单位。
android:scrollbarFadeDuration 设置滚动条淡出效果(从有到慢慢的变淡直至消失)时间,以毫秒为单位。Android22中滚动条滚动完之后会消失,再滚动又会出来,在15、16版本里面会一直显示着。
android:scrollbarSize 设置滚动条的宽度。
android:scrollbarStyle 设置滚动条的风格和位置。设置值:insideOverlay、insideInset、outsideOverlay、outsideInset。这里没有试出太多效果,以下依次是outsideOverlay与outsideInset效果截图比较:
android:scrollbarThumbHorizontal 设置水平滚动条的drawable(如颜色)。
android:scrollbarThumbVertical 设置垂直滚动条的drawable(如颜色)
android:scrollbarTrackHorizontal 设置水平滚动条背景(轨迹)的色drawable(如颜色)
android:scrollbarTrackVertical 设置垂直滚动条背景(轨迹)的drawable注意直接设置颜色值如”android:color/white”将得出很难看的效果,甚至都不理解这个属性了,这里可以参见ApiDemos里res/drawable/ scrollbar_vertical_thumbxml和scrollbar_vertical_trackxml,设置代码为:android:scrollbarTrackVertical="@drawable/scrollbar_vertical_track"
android:scrollbars 设置滚动条显示。none(隐藏),horizontal(水平),vertical(垂直)。见下列代码演示使用该属性让EditText内有滚动条。但是其他容器如LinearLayout设置了但是没有效果。
android:soundEffectsEnabled 设置点击或触摸时是否有声音效果
android:tag 设置一个文本标签。可以通过ViewgetTag()或 for with ViewfindViewWithTag()检索含有该标签字符串的View。但一般最好通过ID来查询View,因为它的速度更快,并且允许编译时类型检查。
android:visibility 设置是否显示View。设置值:visible(默认值,显示),invisible(不显示,但是仍然占用空间),gone(不显示,不占用空间)
和设置状态栏方法相反啊,获得你的windowmanager,然后看他的flag,如果对应状态栏隐藏的那一位是1就是隐藏了,是0就没隐藏。或者获取你的activity的物理坐标,如果达到屏幕高度那就是隐藏了啊
View类提供了setSystemUiVisibility和getSystemUiVisibility方法,这两个方法实现对状态栏的动态显示或隐藏的 *** 作,以及获取状态栏当前可见性。
setSystemUiVisibility方法传入的实参分析:
setSystemUiVisibility(int visibility)方法可传入的实参为:
1 ViewSYSTEM_UI_FLAG_VISIBLE:显示状态栏,
Activity不全屏显示(恢复到有状态的正常情况)。
2 ViewINVISIBLE:隐藏状态栏,同时Activity会伸展全屏显示。
3 ViewSYSTEM_UI_FLAG_FULLSCREEN:Activity全屏显示,且状态栏被隐藏覆盖掉。
4 ViewSYSTEM_UI_FLAG_LAYOUT_FULLSCREEN:Activity全屏显示,但状态栏不会被隐藏覆盖,状态栏依然可见,Activity顶端布局部分会被状态遮住。
5 ViewSYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION:效果同ViewSYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
6 ViewSYSTEM_UI_LAYOUT_FLAGS:效果同ViewSYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
7 ViewSYSTEM_UI_FLAG_HIDE_NAVIGATION:隐藏虚拟按键(导航栏)。有些手机会用虚拟按键来代替物理按键。
8 ViewSYSTEM_UI_FLAG_LOW_PROFILE:状态栏显示处于低能显示状态(low profile模式),状态栏上一些图标显示会被隐藏。
/
随手记中可以任意旋转的炫酷饼图的实现原理
小记:
在实现的过程中,主要是用到了一些数学计算来实现角度和屏幕位置坐标的计算
关于任意两个点之间的角度计算的问题,一开始想了很久没有结果,最后,一个偶然的灵光,让整个
事情变得简单起来,就是计算任意两个点相对于中心坐标的角度的时候,首先,计算
每个点相对于x轴正方向的角度,这样,总可以将其转化为计算直角三角形的内角计算问题
再将两次计算的角度进行减法运算,就实现了。是不是很简单?呵呵,对于像我们这样数学
没有学好的开发者来说,也只有这样化难为简了
@author liner
/
public class PieChart extends View{
public static final String TAG = "PieChart";
public static final int ALPHA = 100;
public static final int ANIMATION_DURATION = 800;
public static final int ANIMATION_STATE_RUNNING = 1;
public static final int ANIMATION_STATE_DOWN = 2;
/
不要问我这个值是怎么设置的。这个就是中的一大块圆形区域对应的长方形四个边的坐标位置
具体的值,自己需要多次尝试并调整了。这样,我们的饼图就是相对于这个区域来画的
/
private static final RectF OVAL = new RectF(18,49,303,340);
private int[] colors; //每部分的颜色值
private int[] values; //每部分的大小
private int[] degrees; //值转换成角度
private String[] titles; //每部分的内容
private Paint paint;
private Paint maskPaint;
private Paint textPaint;
private Point lastEventPoint;
private int currentTargetIndex = -1;
private Point center; //这个是饼图的中心位置
private int eventRadius = 0; //事件距离饼图中心的距离
//测试的时候使用的
//private ChartClickListener clickListener;
private Bitmap mask; //用于遮罩的Bitmap
private int startDegree = 90; //让初始的时候,圆饼是从箭头位置开始画出的
private int animState = ANIMATION_STATE_DOWN;
private boolean animEnabled = false;
private long animStartTime;
public PieChart(Context context) {
super(context);
init();
}
public PieChart(Context context, AttributeSet attrs){
this(context, attrs, 0);
}
public PieChart(Context context, AttributeSet attrs, int defStyle){
super(context, attrs, defStyle);
init();
}
private void init(){
paint = new Paint();
maskPaint = new Paint();
textPaint = new Paint();
textPaintsetColor(ColorWHITE);
textPaintsetTypeface(TypefaceDEFAULT_BOLD);
textPaintsetAlpha(100);
textPaintsetTextSize(16);
values = new int[]{
60,
90,
30,
50,
70
};
//titles = new String[]{
//"川菜",
//"徽菜",
//"粤菜",
//"闽菜",
//"湘菜"
//};
//测试文字居中显示
titles = new String[]{
"我是三岁",
"说了算四大皆空",
"士大",
"史蒂芬森地",
"湘"
};
colors = new int[]{
Colorargb(ALPHA, 249, 64, 64),
Colorargb(ALPHA, 0, 255, 0),
Colorargb(ALPHA, 255, 0, 255),
Colorargb(ALPHA, 255, 255, 0),
Colorargb(ALPHA, 0, 255, 255)
};
degrees = getDegrees();
//Drawable d = getResources()getDrawable(Rdrawablemask);
mask = BitmapFactorydecodeResource(getResources(), Rdrawablemask);
//获取初始位置的时候,下方箭头所在的区域
animEnabled = true; //同时,启动动画
}
//public void setChartClickListener(ChartClickListener l){
//thisclickListener = l;
//}
//计算总和
private int sum(int[] values){
int sum = 0;
for(int i=0; i<valueslength;i++){
sum += values[i];
}
return sum;
}
/
根据每部分所占的比例,来计算每个区域在整个圆中所占的角度
但是,有个小细节,就是计算的时候注意,可能并不能整除的情况,这个时候,为了
避免所有的角度和小于360度的情况,姑且将剩余的部分送给某个部分,反正也不影响
@return
/
private int[] getDegrees(){
int sum = thissum(values);
int[] degrees = new int[valueslength];
for(int i=0; i<valueslength; i++){
degrees[i] = (int)Mathfloor((double)((double)values[i]/(double)sum)360);
//Logv("Angle", angles[i]+"");
}
int angleSum = thissum(degrees);
if(angleSum != 360){
//上面的计算可能导致和小于360
int c = 360 - angleSum;
degrees[valueslength-1] += c; //姑且让最后一个的值稍大点
}
return degrees;
}
/
重写这个方法来画出整个界面
/
protected void onDraw(Canvas canvas) {
superonDraw(canvas);
if(animEnabled){
/
说明是启动的时候,需要旋转着画出饼图
/
Loge(TAG, "anim enabled");
if(animState == ANIMATION_STATE_DOWN){
animStartTime = SystemClockuptimeMillis();
animState = ANIMATION_STATE_RUNNING;
}
final long currentTimeDiff = SystemClockuptimeMillis() - animStartTime;
int currentMaxDegree = (int)((float)currentTimeDiff/ANIMATION_DURATION360f);
Loge(TAG, "当前最大的度数为:"+currentMaxDegree);
if(currentMaxDegree >= 360){
//动画结束状态,停止绘制
currentMaxDegree = 360;
animState = ANIMATION_STATE_DOWN;
animEnabled = false;
}
int[] degrees = getDegrees();
int startAngle = thisstartDegree;
//获取当前时刻最大可以旋转的角度所位于的区域
int maxIndex = getEventPart(currentMaxDegree);
//根据不同的颜色画饼图
for(int i=0; i<= maxIndex; i++){
int currentDegree = degrees[i];
if(i== maxIndex){
//对于当前最后一个绘制区域,可能只是一部分,需要获取其偏移量
currentDegree = getOffsetOfPartStart(currentMaxDegree, maxIndex);
}
if(i > 0){
//注意,每次画饼图,记得计算startAngle
startAngle += degrees[i-1];
}
paintsetColor(colors[i]);
canvasdrawArc(OVAL, startAngle, currentDegree, true, paint);
}
if(animState == ANIMATION_STATE_DOWN){
//如果动画结束了,则调整当前箭头位于所在区域的中心方向
onStop();
}else{
postInvalidate();
}
}else{
int[] degrees = getDegrees();
int startAngle = thisstartDegree;
/
每个区域的颜色不同,但是这里只要控制好每个区域的角度就可以了,整个是个圆
/
for(int i=0; i<valueslength; i++){
paintsetColor(colors[i]);
if(i>0){
startAngle += degrees[i-1];
}
canvasdrawArc(OVAL, startAngle, degrees[i], true, paint);
}
}
/
画出饼图之后,画遮罩,这样就位于饼图之上了,形成了遮罩的效果
/
canvasdrawBitmap(mask, 0, 0, maskPaint);
/
根据当前计算得到的箭头所在区域显示该区域代表的信息
/
if(currentTargetIndex >= 0){
String title = titles[currentTargetIndex];
textPaintsetColor(colors[currentTargetIndex]);
//简单作个计算,让文字居中显示
int width = titlelength()17;
canvasdrawText(title, 157-width/2+3, 383, textPaint);
}
}
/
处理饼图的转动
/
public boolean onTouchEvent(MotionEvent event){
if(animEnabled && animState == ANIMATION_STATE_RUNNING){
return superonTouchEvent(event);
}
Point eventPoint = getEventAbsoluteLocation(event);
computeCenter(); //计算中心坐标
//计算当前位置相对于x轴正方向的角度
//在下面这个方法中计算了eventRadius的
int newAngle = getEventAngle(eventPoint, center);
int action = eventgetAction();
switch (action) {
case MotionEventACTION_DOWN:
lastEventPoint = eventPoint;
if(eventRadius > getRadius()){
/
只有点在饼图内部才需要处理转动,否则直接返回
/
Loge(TAG, "当前位置超出了半径:"+eventRadius+">"+getRadius());
return superonTouchEvent(event);
}
break;
case MotionEventACTION_MOVE:
//这里处理滑动
rotate(eventPoint, newAngle);
//处理之后,记得更新lastEventPoint
lastEventPoint = eventPoint;
break;
case MotionEventACTION_UP:
onStop();
break;
default:
break;
}
return true;
}
/
当我们停止旋转的时候,如果当前下方箭头位于某个区域的非中心位置,则我们需要计算
偏移量,并且将箭头指向中心位置
/
private void onStop() {
int targetAngle = getTargetDegree();
currentTargetIndex = getEventPart(targetAngle);
int offset = getOffsetOfPartCenter(targetAngle, currentTargetIndex);
/
offset>0,说明当前箭头位于中心位置右边,则所有区域沿着顺时针旋转offset大小的角度
offset<0,正好相反
/
startDegree += offset;
postInvalidateDelayed(200);
}
private void rotate(Point eventPoint, int newDegree) {
//计算上一个位置相对于x轴正方向的角度
int lastDegree = getEventAngle(lastEventPoint, center);
/
其实转动就是不断的更新画圆弧时候的起始角度,这样,每次从新的起始角度重画圆弧就形成了转动的效果
/
startDegree += newDegree-lastDegree;
//转多圈的时候,限定startAngle始终在-360-360度之间
if(startDegree >= 360){
startDegree -= 360;
}else if(startDegree <= -360){
startDegree += 360;
}
Loge(TAG, "当前startAngle:"+startDegree);
//获取当前下方箭头所在的区域,这样在onDraw的时候就会转到不同区域显示的是当前区域对应的信息
int targetDegree = getTargetDegree();
currentTargetIndex = getEventPart(targetDegree);
//请求重新绘制界面,调用onDraw方法
postInvalidate();
}
/
获取当前事件event相对于屏幕的坐标
@param event
@return
/
protected Point getEventAbsoluteLocation(MotionEvent event){
int[] location = new int[2];
thisgetLocationOnScreen(location); //当前控件在屏幕上的位置
int x = (int)eventgetX();
int y = (int)eventgetY();
x += location[0];
y += location[1]; //这样x,y就代表当前事件相对于整个屏幕的坐标
Point p = new Point(x, y);
Logv(TAG, "事件坐标:"+ptoString());
return p;
}
/
获取当前饼图的中心坐标,相对于屏幕左上角
/
protected void computeCenter(){
if(center == null){
int x = (int)OVALleft + (int)((OVALright-OVALleft)/2f);
int y = (int)OVALtop + (int)((OVALbottom - OVALtop)/2f)+50; //状态栏的高度是50
center = new Point(x,y);
//Logv(TAG, "中心坐标:"+centertoString());
}
}
/
获取半径
/
protected int getRadius(){
int radius = (int)((OVALright-OVALleft)/2f);
//Logv(TAG, "半径:"+radius);
return radius;
}
/
获取事件坐标相对于饼图的中心x轴正方向的角度
这里就是坐标系的转换,本例中使用饼图的中心作为坐标中心,就是我们从初中到大学一直使用的"正常"坐标系。
但是涉及到圆的转动,本例中一律相对于x正方向顺时针来计算某个事件在坐标系中的位置
@param eventPoint
@param center
@return
/
protected int getEventAngle(Point eventPoint, Point center){
int x = eventPointx - centerx;//x轴方向的偏移量
int y = eventPointy - centery; //y轴方向的偏移量
//Logv(TAG, "直角三角形两直边长度:"+x+","+y);
double z = Mathhypot(Mathabs(x), Mathabs(y)); //求直角三角形斜边的长度
//Logv(TAG, "斜边长度:"+z);
eventRadius = (int)z;
double sinA = (double)Mathabs(y)/z;
//Logv(TAG, "sinA="+sinA);
double asin = Mathasin(sinA); //求反正玄,得到当前点和x轴的角度,是最小的那个
//Logv(TAG, "当前相对偏移角度的反正弦:"+asin);
int degree = (int)(asin/314f180f);
//Logv(TAG, "当前相对偏移角度:"+angle);
//下面就需要根据x,y的正负,来判断当前点和x轴的正方向的夹角
int realDegree = 0;
if(x<=0 && y<=0){
//左上方,返回180+angle
realDegree = 180+degree;
}else if(x>=0 && y<=0){
//右上方,返回360-angle
realDegree = 360-degree;
}else if(x<=0 && y>=0){
//左下方,返回180-angle
realDegree = 180-degree;
}else{
//右下方,直接返回
realDegree = degree;
}
//Logv(TAG, "当前事件相对于中心坐标x轴正方形的顺时针偏移角度为:"+realAngle);
return realDegree;
}
/
获取当前下方箭头位置相对于startDegree的角度值
注意,下方箭头相对于x轴正方向是90度
@return
/
protected int getTargetDegree(){
int targetDegree = -1;
int tmpStart = startDegree;
/
如果当前startAngle为负数,则直接+360,转换为正值
/
if(tmpStart < 0){
tmpStart += 360;
}
if(tmpStart < 90){
/
如果startAngle小于90度(可能为负数)
/
targetDegree = 90 - tmpStart;
}else{
/
如果startAngle大于90,由于在每次计算startAngle的时候,限定了其最大为360度,所以
直接可以按照如下公式计算
/
targetDegree = 360 + 90 - tmpStart;
部分代码 百度知道限制字数 下载附件查看
使用方案为onWindowFocusChanged()方法
当Activity重新获取焦点时,会调用此方法,从而解决数据以及声音(在程序不可见时可关闭)
当然此方法也不是专门为此设计的,他还有别的用处哦~
该方法在窗口的insets发生变化时,被调用。View调用该方法,以调整内容来适应窗口的变化。窗口的insets变化,包括status bar、软键盘、navigation bar等的显隐。
一般情况下我们不需要关心这个方法。但如果设置 SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN、SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 等标识开启沉浸式,默认情况下,我们的内容区域就会被status bar、软键盘等遮挡。
该方法的默认实现会根据insets值来设置view的padding,并返回true,防止该事件继续传递(即只有一个view会真正fitSystemWindows)。要开启该方法,需要执行 setFitsSystemWindows(true) ,或在XML中设置 android:fitsSystemWindows="true" 。
如果只需要为XML文件的根布局设置fitSystemWindows,该方法的默认实现就能满足。如果需要适配更加复杂的布局(比如有两个子View,一个在顶部,一个在底部,则顶部的需要根据insets设置paddingTop,底部的需要根据insets设置paddingBottom),你就需要重写该方法,自行处理insets。
需要说明的是,如果不做任何处理,所有view接收到的insets都是一样的(比如top是status bar的高度,bottom是软键盘的高度)。该方法的执行在layout之前。
WindowInsets
该类封装了几种不同的insets。 mSystemWindowInsets 对应status bar、软键盘等引起的insets。可用方法如下:
获取四个边的inset
消费掉insets,使之不再传递
生成新的WindowInsets对象
该方法会被第一个调用,如果设置了listener,则执行自定义的listener,否则执行 onApplyWindowInsets 。
默认情况下该方法会执行第一个分支,即执行上面的 fitSystemWindows 。api20以上,android建议覆写该方法,而不是已废弃的 fitSystemWindows 。
监听fitSystemWindow事件。
listener类如下:
ViewGroup:
可以看到,从根布局开始,先执行本身的 superdispatchApplyWindowInsets 方法,然后遍历执行子View的 dispatchApplyWindowInsets 方法,如果被消费掉,则停止传递。
布局如下:
设置沉浸式:
设置软键盘适配方式:
现在布局是这个样子的:
图1标题栏被状态栏遮挡,图2页面被软键盘遮挡。
再次强调一个概念,默认情况下,设置 android:fitsSystemWindows="true" 只有一个View会生效。
为根布局设置 android:fitsSystemWindows="true" ,同时为了方便观察,给根布局设置一个灰色背景:
可以看到已经适配了软键盘,但顶部toolbar区域也显示了根布局的灰色背景,显然默认实现满足不了我们的需求。
解决方式有很多,这里介绍两种比较优雅的方式。
首先需要为Toolbar也设置 android:fitsSystemWindows="true"
达到了预期效果。
自定义根布局
自定义toolbar
两种方法实际上是等价,不过显然还是第一种方式更友好,只需要设置一个listener就能搞定,但因为api版本限制,所以很多情况下还是要使用第二种方式。
如果覆写了 fitSystemWindows(insets) 或者 onApplyWindowInsets(WindowInsets) ,覆写方法中不调用对应的super方法,则不需要设置 setFitsSystemWindows(true) 或者 android:fitsSystemWindows="true" 。
原因如下:
以上就是关于android 代码中设置控件的垂直居中和两个控件之间的距离。全部的内容,包括:android 代码中设置控件的垂直居中和两个控件之间的距离。、android 判断状态栏是否隐藏、Android中如何收起状态栏等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)