https://developer.android.google.cn
具体详见:https://blog.csdn.net/weixin_45048331/article/details/111868109
修改工程结构显示方式,将Android修改成Project[以目录结构显示];为不影响显示效果此部分内容请使用PC端查看
├── .gradle # AS自动生成的文件,AS会自动修改它的,项目打包时也会删除;
├── .idea # AS自动生成的文件,AS会自动修改它的,项目打包时也会删除;
├── app # 应用相关的东西都在里面,工作的核心目录
│ ├── build # 编译的产物。某些情况下,可以手动把它整个删掉。
│ ├── libs # 依赖包可以放这里,比如一些jar文件。
│ ├── src # 代码在这。非常重要。
│ │ ├── main
│ │ │ ├── java # 放Java代码的地方
│ │ │ ├── res
│ │ │ │ ├── drawable # 应用图标
│ │ │ │ ├── layout # Android布局文件夹
│ │ │ │ ├── mipmap # 桌面图标
│ │ │ │ ├── layout # Android布局文件夹
│ │ │ │ └── values # 颜色、样式、字符集配置文件夹
│ ├── .gitignore # 版本控制
│ ├── build.gradle # 非常重要,app的构建配置。俗称“app的gradle文件”。
│ └── proguard-rules.pro # 先不管。这个是混淆配置。
├── gradle # 它是一个构建起配置文件
├── .gitignore # 整个工程的版本控制
├── build.gradle # 很重要。项目级的配置。俗称“项目gradle文件”。
├── gradle.properties # 全局的gradle配置文件
├── gradlew # Linux/mac上执行gradle命令
├── gradlew.bat # Windows上执行gradle命令
├── local.properties # 本地配置文件,一般不上传
└── settings.gradle # gralde的项目级配置
注:控件的属性值可以【Ctrl+鼠标左键】进行查看
本节前言:
dp(dip): device independent pixels(设备独立像素). 不同设备有不同的显示效果,这个和设备硬件有关,一般我们为了支持WVGA、HVGA和QVGA 推荐使用这个,不依赖像素。
px: pixels(像素). 不同设备显示效果相同,一般我们HVGA代表320x480像素,这个用的比较多。
pt: point,是一个标准的长度单位,1pt=1/72英寸,用于印刷业,非常简单易用;
sp: scaled pixels(放大像素). 主要用于字体显示best for textsize。
XML代码:
XML代码:
更多详见:TextView(文本框)详解 | 菜鸟教程 (runoob.com)
XML代码:
默认情况下没有效果:
本节前言:
Button是TextView的子类,所以TextView上很多属性也可以应用到Button 上!我们实际开发中对于Button的,无非是对按钮的几个状态做相应的操作,比如:按钮按下的时候 用一种颜色,弹起又一种颜色,或者按钮不可用的时候一种颜色这样!上述实现无非是通过 StateListDrawable这种Drawable资源来实现,即编写一个drawable的资源文件。
StateListDrawable是Drawable资源的一种,可以根据不同的状态,设置不同的图片效果,关键节点 < selector >,我们只需要将Button的background属性设置为该drawable资源即可轻松实现,按下 按钮时不同的按钮颜色或背景!
更多详见:Button(按钮)与ImageButton(图像按钮) | 菜鸟教程 (runoob.com)
XML代码:
运行效果图:
代码中TAG的值为“leo”
运行结果1(长按+移动):setOnLongClickListener()与setOnTouchListener()的返回值为false
运行结果2(长按+移动):setOnLongClickListener()返回值为false,setOnTouchListener()的返回值为true,会将setOnLongClickListener()取代(即触摸/移动也会触发)
运行结果3(长按+移动):setOnLongClickListener()返回值为true,setOnTouchListener()的返回值为false,setOnClickListener()不会执行
onClickListener()的另一种写法:在activity_main.xml的Button标签中写android:onClick="leoClick",再按住Alt+Enter创建leoClick方法,优先级低于setOnClickListener()
更多详见:EditText(输入框)详解 | 菜鸟教程 (runoob.com)
XML代码:
XML代码:
更多详见:ImageView(图像视图) | 菜鸟教程 (runoob.com)
更多详见:ProgressBar(进度条) | 菜鸟教程 (runoob.com)
XML代码:
Java代码:
public class MainActivity extends AppCompatActivity {
private ProgressBar pb1;
private ProgressBar pb2;
private Integer speed;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pb1 = findViewById(R.id.pb1);
pb2 = findViewById(R.id.pb2);
speed = (int)(pb2.getMax() * 0.1);
}
public void leoClick(View view) {
if (pb1.getVisibility() == View.GONE) {
pb1.setVisibility(View.VISIBLE); //显示
} else {
pb1.setVisibility(View.GONE);
}
}
public void loadClick(View view) {
int progress = pb2.getProgress();
pb2.setProgress(progress + speed);
}
}
状态通知栏主要涉及到2个类:Notification 和NotificationManager
Notification:通知信息类,它里面对应了通知栏的各个属性
NotificationManager:是状态栏通知的管理类,负责发通知、清除通知等操作。
使用的基本流程:
通知渠道,Android 8.0引入了通知渠道,其允许您为要显示的每种通知类型创建用户可自定义的渠道。
通知重要程度设置,NotificationManager类中
注意:Android从5.0系统开始,对于通知栏图标的设计进行了修改。现在Google要求,所有应用程序的通知栏图标,应该只使用alpha图层来进行绘制,而不应该包括RGB图层。
XML代码:
Java代码:
运行效果:
更多详见:Notification(状态栏通知)详解 | 菜鸟教程 (runoob.com)
取消系统默认的标题栏目:src/main/res/values/themes.xml --> style标签 --> parent="Theme.MaterialComponents.DayNight.NoActionBar"
使用ToolBar替换系统默认的DarkActionBar:
XML代码:
Java代码:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.tb); //androidx.appcompat.widget.Toolbar
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.e("leo","ToolBar被点击了!");
}
});
}
}
使用流程:
- Step 1:创建AlertDialog.Builder对象;
- Step 2:调用setIcon()设置图标,setTitle()或setCustomTitle()设置标题;
- Step 3:设置对话框的内容:setMessage()还有其他方法来指定显示的内容;
- Step 4:调用setPositive/Negative/NeutralButton()设置:确定,取消,中立按钮;
- Step 5:调用create()方法创建这个对象,再调用show()方法将对话框显示出来;
更多详见:AlertDialog(对话框)详解 | 菜鸟教程 (runoob.com)
XML代码:
Java代码:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "leo";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void leoClick(View view) {
AlertDialog.Builder builder = new AlertDialog.Builder(this); //androidx.appcompat.app.AlertDialog;
builder.setIcon(R.mipmap.ic_launcher)
.setTitle("对话框")
.setMessage("今天天气怎么样?")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Log.e(TAG, "点击了确定按钮");
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Log.e(TAG, "点击了取消按钮");
}
})
.setNeutralButton("中间/其他", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Log.e(TAG, "点击了中间/其他按钮");
}
})
.create()
.show(); //最后两个位置不能交换
}
}
dialog_view.xml代码:
更多详见: PopupWindow(悬浮框)的基本使用 | 菜鸟教程 (runoob.com)
XML代码:
popup_view.xml代码:
Java代码:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "leo";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void leoClick(View view) {
View popupView = getLayoutInflater().inflate(R.layout.popup_view, null);
//视图、宽、高、是否获取焦点(点击空白处取消)
PopupWindow popupWindow = new PopupWindow(popupView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);
popupWindow.setBackgroundDrawable(getResources().getDrawable(R.drawable.ceshi)); //设置背景
popupWindow.showAsDropDown(view, 50,0);
Log.e(TAG, "leoClick: 111111");
Button btn1 = popupView.findViewById(R.id.btn1);
Button btn2 = popupView.findViewById(R.id.btn2);
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.e(TAG, "onClick: 按钮1被点击");
}
});
btn2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.e(TAG, "onClick: 按钮2被点击");
}
});
}
}
更多详见:LinearLayout(线性布局) | 菜鸟教程 (runoob.com)
XML代码:
margin设置组件与父容器的边距
padding设置组件与子容器的边距
更多详见:RelativeLayout(相对布局) | 菜鸟教程 (runoob.com)
XML代码:
运行效果图:
更多详见:TableLayout(表格布局) | 菜鸟教程 (runoob.com)
XML代码:
更多详见:FrameLayout(帧布局) | 菜鸟教程 (runoob.com)
XML代码:
更多详见:GridLayout(网格布局) | 菜鸟教程 (runoob.com)
XML代码:
ConstraintLayout
采用方向约束的方式对控件进行定位,至少要保证水平和垂直方向都至少有一个约束才能确定控件的位置
我自己的XX位置和谁的YY位置对齐
注意:前四个不能与后四个的对应(Left-->Start、Right-->End)效果相同,但是它们不能交叉使用,否则后者无效果,后面内容同理
XML代码:
外边距(margin):
内边距(padding):
goneMargin:
goneMargin是一个依赖于目标的属性,当依赖的目标隐藏(android:visibility="gone")时才会生效,例如A被B依赖约束,当A隐藏时B设置的goneMargin就会生效,为不影响布局,往往会为B控件设置goneMargin,属性如下:
XML代码:
运行效果:
约束控件的最小、最大尺寸:
控件大小的0dp值:
设置控件的大小除了传统的wrap_content 、指定具体尺寸、match_parent 外,ConstraintLayout还可以设置为0dp (MATCH_CONSTRAINT),并且 0dp的作用会根据设置的类型而产生不同的作用,进行设置类型的属性是:
- layout_constraintWidth_default:水平方向控制
- layout_constraintHeight_default:垂直方向控制
其属性可取值如下:
注意:当空间的尺寸设置成wrap_content时内容占用的空间会去侵占margin部分,可通过以下属性是否强制限制
0dp下的其他属性值:
XML代码:
ConstraintLayout中可以对宽高设置比例,前提是至少有一个约束维度设置为0dp,这样比例才会生效,若两个都设置为0dp则以父元素的宽作为参考,该属性可使用两种设置:
- app:layout_constraintDimensionRatio="宽度:高度":表示宽度和高度之间形式的比率
- app:layout_constraintDimensionRatio="浮点值":表示宽度和高度之间的比率
注意:两个属性都有两个参数,第一个参数(W/H)可以省略,W表示宽度通过壁纸计算得来,H表示高度通过壁纸计算得来
XML代码:
Chains(链)它是将许多个控件在水平或者垂直方向,形成一条链,用于平衡这些控件的位置,设置成链的方式如下:
layout_constraintHorizontal_chainStyle:水平成链
layout_constraintVertical_chainStyle:垂直成链
可以属性如下:
Chains(链)还支持
weight(权重)
的配置,使用如下属性进行设置链元素的权重:
layout_constraintHorizontal_weight:水平方向权重分配
layout_constraintVertical_weight:垂直方向权重分配
注意:若需要进行权重设置,则该方向的上的尺寸设置为0dp
Chains(链)还支持
bias(偏移)
的配置,使用如下属性进行设置链元素的偏移:
layout_constraintHorizontal_bias:水平方向偏移,0.5表示居中
layout_constraintVertical_bias:垂直方向的偏移,0.5表示居中
XML代码:
ConstraintLayout
为了解决嵌套问题还提供了一系列的辅助控件帮助开发者布局
Guideline
是一条参考线,可以帮助开发者进行辅助定位,它并不会真正显示在布局中,像是数学几何中的辅助线一样
XML代码:
当我们创建Android布局时,有时我们会遇到布局可以根据本地化而变化的情况。下面是一个来自于约束布局 (constraintlayout.com)非常简单的示例:
这里有三个文本视图:左边的
textView1
和textView2
;右边的textView3
。textView3
被限制在textView1
的末尾,这工作得很好——它完全根据我们需要来定位和大小textView3
。然而,如果我们需要支持多种语言,事情会变得更加复杂。如果我们添加德语翻译,那么我们就会遇到一个问题,因为在英文版本中,textView1
中的文本比textView2
中的文本长,而在德语中,textView2
中的文本比textView1
长:
这里的问题在于
textView3
仍然是相对于textView1
的,所以textView2
直接插入了textView3
中。在设计视图里看起来更明显(白色背景的那个)。比较直接的解决办法是使用TableLayout
,或者把textView1
&textView2
包裹在一个垂直的,android:layout_width="wrap_content"
的LinearLayout中
。然后让textView3
约束在这个LinearLayout
的后面。但是我们有更好的办法:Barriers
。Barriers
的配置属性如下:
ConstraintLayout
中的Group
的作用是对一组控件同时隐藏或显示,没有其他的作用,它的属性如下:
XML代码:
Java代码:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
Button btn1,btn2;
Group group1,group2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_group);
btn1 = findViewById(R.id.btn1);
group1 = findViewById(R.id.group1);
btn2 = findViewById(R.id.btn2);
group2 = findViewById(R.id.group2);
btn1.setOnClickListener(this);
btn2.setOnClickListener(this);
}
@Override
public void onClick(View view) {
if (view.getId() == btn1.getId()){
group1.setVisibility(group1.getVisibility()==Group.VISIBLE?Group.INVISIBLE:Group.VISIBLE);
} else{
group2.setVisibility(group2.getVisibility()==Group.VISIBLE?Group.INVISIBLE:Group.VISIBLE);
}
}
}
运行效果图:
Placeholder
的作用就是占位,它可以在布局中占好位置,通过app:content=""
属性,或者动态调用setContent()
设置内容,来让某个控件移动到此占位符中
XML代码:
Java代码:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
Placeholder placeholder;
TextView tv1,tv2;
ConstraintLayout mConstraintLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_placeholder);
Button btn1 = findViewById(R.id.btn1);
placeholder = findViewById(R.id.p);
tv1 = findViewById(R.id.A);
tv2 = findViewById(R.id.B);
mConstraintLayout = findViewById(R.id.constraintLayout);
btn1.setOnClickListener(this);
}
@Override
public void onClick(View view) {
TransitionManager.beginDelayedTransition(mConstraintLayout);
if (placeholder.getContent() == null) {
System.out.println(tv1.getId());
placeholder.setContentId(tv1.getId());
}else {
if (placeholder.getContent().getId()==tv1.getId()){
placeholder.setContentId(tv2.getId());
}else {
placeholder.setContentId(tv1.getId());
}
}
}
}
注意:设置文本内容时样式发生了改变,而且placeholder不知如何还原初态
Flow
是用于构建链的新虚拟布局,当链用完时可以缠绕到下一行甚至屏幕的另一部分。当您在一个链中布置多个项目,但是您不确定容器在运行时的大小时,这很有用。您可以使用它来根据应用程序中的动态尺寸(例如旋转时的屏幕宽度)构建布局。
1. 链约束(针对的时超出屏幕部分)
Flow
的constraint_referenced_ids
关联的控件是没有设置约束的,这一点和普通的链是不一样的,这种排列方式是Flow
的默认方式none
,我们可以使用app:flow_wrapMode=""
属性来设置排列方式,并且我们还可以使用flow_horizontalGap
和flow_verticalGap
分别设置两个view
在水平和垂直方向的间隔,下面我们再添加几个控件来展示三种排列方式:
view
形成一条链,水平居中,超出屏幕两侧的view
不可见view
形成一条链,超出部分会自动换行,同行的view
会平分宽度,纵横平均分配Flow空间view
形成一条链,超出部分会自动换行,同行的view
会平分宽度,纵向平均分配Flow空间,横向的view
会从start
处开始排列,默认从左往右排列当
flow_wrapMode
的值是chian
或aligned
时,我们还可以针对不同的链进行配置,这里就不一一展示效果了,具体的属性如下:
app:flow_wrapMode="chian"
)app:flow_wrapMode="aligned"
)XML代码:
2. 对齐约束
当
view
的大小不同时,Flow
也提供了相应的属性进行配置(flow_wrapMode="aligned"
时,我试着没有效果)。使用
flow_verticalAlign
时,要求orientation
的方向是horizontal
,使用
flow_horizontalAlign
时,要求orientation
的方向是vertical
horizontal 水平排列
垂直方向排列同理
3. 数量约束
当
flow_wrapMode
属性为aligned
或chian
时,通过flow_maxElementsWrap
属性控制每行最大的子View
数量,例如我们设置为flow_maxElementsWrap=4
,效果图如下:
ImageFilterButton
和ImageFilterView
是两个控件,他们之间的关系就和ImageButton
与ImageView
一样,即ImageFilterButton
继承ImageButton
,而ImageFilterView
继承ImageView
,所以这里就只拿ImageFilterView
来做讲解。它们的大致作用有两部分,一是可以用来做圆角图片,二是可以叠加图片资源进行混合过滤,下面一一展示:
1. 圆角图片
ImageFilterButton
和ImageFilterView
可以使用两个属性来设置图片资源的圆角,分别是roundPercent
和round
,roundPercent
接受的值类型是0-1的小数,根据数值的大小会使图片在方形和圆形之间按比例过度,round
可以设置具体圆角的大小。下面请看例子:
2. 图片过滤
ImageFilterButton
和ImageFilterView
不但可以使用src
来设置图片资源,还可以使用altSrc
来设置第二个图片资源,altSrc
提供的资源将会和src
提供的资源通过crossfade
属性形成交叉淡化效果,默认情况下,crossfade=0
,altSrc
所引用的资源不可见,取值在0-1。下面看例子:
XML代码:
除此之外,还有以下属性(取值范围为:0-10):
warmth
:调节色温brightness
:调节亮度saturation
:调节饱和度contrast
:调节对比度