Android_开发_Day22_图案解锁(上)
Android_开发Day22图案解锁
目的:
体验各种布局带来的效果,能够合理的运用布局,学会使用代码来添加控件,以及代码和xml的配合使用
技术:
<1> Layout布局:
布局分为FrameLayout LinearLayout RelativeLayout ConstraintLayout,下面依次来讲解:
LinearLayout:线性布局是一个挨着一个拼起来的,线性布局可以往左边拼,也可以往右边拼,线性布局中用到的方法如下:
名称 | 作用 |
---|---|
layout_marginTop | 控件的上方与外界的偏移 |
layout_marginBottom | 控件的下方与外界的偏移 |
layout_marginLeft | 控件的左边与外界的偏移 |
layout_marginRight | 控件右边与外界的偏移 |
orientation | 改变布局方式(向左边拼还是向右边拼) |
layout_weight | 如果视图中有多个控件时,可以分配该控件的权重,如1:1的权重就是平分 |
RelativeLayout相对布局:它是一个相对布局,即A控件相对于B控件的布局位置是多少,下面是常用的方法:
名称 | 作用 |
---|---|
layout_alignTop | 控件与其余控件上对齐 |
layout_alignBottom | 控件与其余控件下对齐 |
layout_alignRight | 控件与其余控件右对齐 |
layout_alignLeft | 控件与其余控件左对齐 |
layout_alignParentBottom | 与父类底对齐 |
layout_alignParentTop | 与父类顶对其 |
layout_alignParentLeft | 与父类左对齐 |
layout_alignParentRight | 与父类右对齐 |
layout_marginHorizontal | 与父类左对齐并设置间距 |
layout_marginVertical | 与父类顶对齐并设置间距 |
layout_centerInParent | 在父类的中心 |
layout_centerVertical | 在父类的纵向中心 |
layout_centerHorizontal | 在父类的横向中心 |
ayout_marginTop | 控件的上方与外界的偏移 |
layout_marginBottom | 控件的下方与外界的偏移 |
layout_marginLeft | 控件的左边与外界的偏移 |
layout_marginRight | 控件右边与外界的偏移 |
ConstraintLayout约束布局:通过约束条件来放控件,因此不能写死宽高,常用方法如下:
名称 | 作用 |
---|---|
layout_marginTop | 控件的上方与外界的偏移 |
layout_marginBottom | 控件的下方与外界的偏移 |
layout_marginLeft | 控件的左边与外界的偏移 |
layout_marginRight | 控件右边与外界的偏移 |
layout_marginHorizontal | 与父类左对齐并设置间距 |
layout_marginVertical | 与父类顶对齐并设置间距 |
layout_constraintTop_toTopOf | 顶与顶挨着 |
layout_constraintTop_toBottomOf | 顶与底挨着 |
layout_constraintBottom_toBottomOf | 底与底挨着 |
layout_constraintBottom_toTopOf | 底与顶挨着 |
layout_constraintLeft_toLeftOf | 左与左挨着 |
layout_constraintLeft_toRightOf | 左与右挨着 |
layout_constraintRight_toRightOf | 右与右挨着 |
layout_constraintRight_toLeftOf | 右与左挨着 |
layout_constraintDimensionRatio | 按比例放控件,如h,1:2表示宽高比是1:2 |
layout_constraintHorizontal_weight | 横向比列分 |
layout_constraintVertical_weight | 纵向比例分 |
<2> onWindowFocusChanged:
onWindowFocusChanged方法是系统调用的,当应用成为焦点时会调用,也就是说当该方法调用的时候容器中的控件的尺寸已经测量完毕了,因此可以用该方法来获取控件的尺寸,同时说一下,在onCreate方法中显示控件尺寸时是得不到的,因为控件尺寸的测量是在一个线程中完成的,因此在调用onCreate方法时不能判断测量线程是否测量完毕,因此99.9%的都得不到尺寸,而onWindowFocusChanged刚好就是在测量线程完成之后才调用的。
<3> 屏幕适配:
由于各种品牌的手机的屏幕大小以及屏幕密度都存在差异,因此同样一张大小的图片在系统加载它时加载出来的尺寸就会不一样,具体怎么回事我还不知道,但是能够确定的是,图片的分辨率是等比放大或缩小的,并且倍数刚好是scale,因为不同手机的scale倍数不一样所以图片被缩放的大小就不一样,但是有一个不变的就是原图的大小是不变的,因此我们只需要知道原图的某个位置在原图的坐标再将它放大scale倍就可以得到它在不同手机中的坐标了,scale的获取可以用getResources().getDisplayMetrics().density来获取。
技术如何使用:
要做一个图案解锁首先需要搭建界面,界面分为背景图片和前景图片,这里背景图片自己选择,由于是静态的所以可以直接在xml里面写,前景图片是9个点和若干线和一个9个点的框架,框架是不动的因此可以用xml写,9个点和若干线理论上也是不动的因此可以用xml来写,但是由于数量过于多了,用xml来写就会很复杂,因此考虑用代码的for循环来自动添加每个点,因此需要添加好一个点首先需要坐标,这里的坐标可以用框架的坐标加上该点在框架内部相对于框架的坐标,前面说了,框架图片会被系统缩放因此,需要将原图的某个位置在原图的坐标将它放大scale倍才能得到真正的坐标,然后加上框架的坐标就是点的坐标了,然后用for循环重复此步骤,必要时换行就行了,创建界面的代码如下:
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
//获取屏幕密度
float a = getResources().getDisplayMetrics().density;
//判断是否已经显示
if (hasFocus) {
//获取容器
RelativeLayout rl = findViewById(R.id.cl_main);
//获取背景视图
ImageView iv = findViewById(R.id.opView);
//获取x和y
int x = iv.getLeft();
int y = iv.getTop();
//创建横线
tag = 1;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
//创建一个视图显示线
ImageView lineView = new ImageView(this);
//设置图片
lineView.setBackgroundResource(R.drawable.normal_highlight1);
//设置tag值
tag+=11;
lineView.setTag(tag);
//加tag值
lineList.add(tag);
//创建布局参数
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.leftMargin = (int) (x + 46.6 * a + 99 * a * j);
params.topMargin = (int) (y + 170 * a + 99 * a * i);
rl.addView(lineView, params);
lineView.setVisibility(View.INVISIBLE);
}
tag+=11;
}
//创建竖线
tag = 14;
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
//创建一个视图显示线
ImageView lineView = new ImageView(this);
//设置图片
lineView.setBackgroundResource(R.drawable.normal_highlight2);
//添加tag值
lineView.setTag(tag);
//加tag值
lineList.add(tag);
tag+=11;
//创建布局参数
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.leftMargin = (int) (x + 42 * a + 99 * a * j);
params.topMargin = (int) (y + 170 * a + 99 * a * i);
rl.addView(lineView, params);
lineView.setVisibility(View.INVISIBLE);
}
}
//创建右竖线
tag = 15;
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
//创建一个视图显示线
ImageView lineView = new ImageView(this);
//设置图片
lineView.setBackgroundResource(R.drawable.normal_highlight3);
//添加tag值
lineView.setTag(tag);
//加tag值
lineList.add(tag);
tag+=11;
//创建布局参数
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.leftMargin = (int) (x + 42 * a + 99 * a * j);
params.topMargin = (int) (y + 170 * a + 99 * a * i);
rl.addView(lineView, params);
lineView.setVisibility(View.INVISIBLE);
}
tag+=11;
}
//创建左竖线
tag = 24;
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
//创建一个视图显示线
ImageView lineView = new ImageView(this);
//设置图片
lineView.setBackgroundResource(R.drawable.normal_highlight4);
//设置tag值
lineView.setTag(tag);
//加tag值
lineList.add(tag);
tag+=11;
//创建布局参数
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.leftMargin = (int) (x + 54 * a + 99 * a * j);
params.topMargin = (int) (y + 170 * a + 99 * a * i);
rl.addView(lineView, params);
lineView.setVisibility(View.INVISIBLE);
}
tag+=11;
}
//九个点
tag = 1;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
//创建用于显示点的视图
ImageView dotView = new ImageView(this);
//设置对应的tag值
dotView.setTag(tag++);
//隐藏视图
dotView.setVisibility(View.VISIBLE);
//显示对应的图片
dotView.setBackgroundResource(R.drawable.selected_dot);
//创建控件的尺寸
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.leftMargin = (int) (x + 35 * a + 99 * a * j);
params.topMargin = (int) (y + 164 * a + 99 * a * i);
//将子控件添加到容器中
rl.addView(dotView, params);
dotView.setVisibility(View.INVISIBLE);
//将控件放到数组里面
dotsList.add(dotView);
}
}
}
}
xml里面放一张背景图和前景图,代码如下:
<!--背景图片-->
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"
android:src="@drawable/main_bg"
/>
<!--9个点的框架图片-->
<ImageView
android:id="@+id/opView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/op_bg"
android:layout_centerInParent="true"/>
实际使用效果:

总结:
想要搭建一个好看的界面要学会各种布局,并且需要在合适的情形运用合适的布局去做这样不仅能够节约时间同时也能使布局更加的好看,同时布局中比较重要的就是控件的坐标,也是布局中最容易错的和最难搞的,要弄清楚是相对坐标还是绝对坐标。