- Android基础git地址:https://gitee.com/xiaozhi1998/AndroidBaisi
活动
设置主活动
//在想要设置的活动添加以下代码
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
基础语法
public class FirstActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.first_layout);
//获取按钮
Button button1 = (Button) findViewById(R.id.button_1);
//监听点击
button1.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
//消息提示
Toast.makeText(FirstActivity.this, "You clicked Button 1", Toast.LENGTH_SHORT).show();
}
});
Button button2 = (Button) findViewById(R.id.button_2);
button2.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
//销毁程序
finish();
}
});
Button button3 = (Button) findViewById(R.id.button_3);
button3.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
//显式Intent
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);
}
});
Button button4 = (Button) findViewById(R.id.button_4);
button4.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
//隐式Intent, 只能指定一个action
Intent intent = new Intent("com.example.test02.ACTION_START");
//指定多个category
intent.addCategory("com.example.test02.MY_CATEGORY");
startActivity(intent);
}
});
Button button5 = (Button) findViewById(R.id.button_5);
button5.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
Intent intent = new Intent(Intent.ACTION_VIEW);
//打开浏览器的百度
intent.setData(Uri.parse("http://www.baidu.com"));
startActivity(intent);
}
});
Button button6 = (Button) findViewById(R.id.button_6);
button6.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
Intent intent = new Intent(Intent.ACTION_DIAL);
//拨打10086
intent.setData(Uri.parse("tel:10086"));
startActivity(intent);
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
//获取菜单
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
//菜单点击监听
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()){
case R.id.add_item:
Toast.makeText(FirstActivity.this, "You clicked Add", Toast.LENGTH_SHORT).show();
break;
case R.id.remove_item:
Toast.makeText(FirstActivity.this, "You clicked Remove", Toast.LENGTH_SHORT).show();
break;
default:
Toast.makeText(FirstActivity.this, "You clicked Nothing", Toast.LENGTH_SHORT).show();
}
return true;
}
}
利用元数据传递配置信息
- 在activity节点内部添加meta-data标签
<activity android:name=".MainActivity">
<meta-data android:name="weather" android:value="晴天"/>
</activity>
-
Java代码获取元数据信息
- 调用getPackageManager方法获得当前应用的包管理器
- 调用包管理器的getActivityInfo方法获得当前活动的信息对象
- 活动信息对象的metaData是Bundle包裹类型,调用包裹对象的getString即可获得指定名称的参数值
// 显示配置的元数据 private void showMetaData() { try { PackageManager pm = getPackageManager(); // 获取应用包管理器 // 从应用包管理器中获取当前的活动信息 ActivityInfo act = pm.getActivityInfo(getComponentName(), PackageManager.GET_META_DATA); Bundle bundle = act.metaData; // 获取活动附加的元数据信息 String value = bundle.getString("weather"); // 从包裹中取出名叫weather的字符串 tv_meta.setText("来自元数据信息:今天的天气是"+value); // 在文本视图上显示文字 } catch (Exception e) { e.printStackTrace(); } }
传递数据
Intent
-
Intent用于Android各组件之间的通信,主要完成下列3部分工作
- 标记本次从哪里来、到哪里去、要怎么走
- 发起方携带本次通信需要的数据内容,接收方从收到的意图中解析数据
- 发起方若想判断接收方的处理结果,意图就要负责让接收方传回应答的数据内容
-
七大属性
-
Component,setComponent,组件,指定意图的来源于目标
-
Action,setAction,动作,它指定意图的动作行为
- ACTION_MAIN:App启动时的入口
- ACTION_VIEW:向永固红显示数据
- ACTION_SEND:分享内容
- ACTION_CALL:直接拨号
- ACTION_DIAL:准备拨号
- ACTION_SENDTO:发送短信
- ACTION_ANSWER:接听电话
-
Data,setData,即Uri,指定动作要操作的数据路径,八大类型(Int、Double、Float、Boolean、String、StringArray、StringArrayList、Serializable)
-
Category,addCategory,类别,指定意图的操作类型
-
Type,setType,数据类型,指定消息的数据类型
-
Extras,putExtras,扩展信息,指定装载的包裹信息
-
Flags,setFlags,标志位,指定活动的启动标志
-
-
指定意图对象的目标有两种表达方式:显式Intent和隐式Intent
- 显式Intent,直接指定来源活动和目标活动,属于精确匹配
- 隐式Intent,没有给出明确要跳转的目标活动,只给出一个动作字符串让系统自动匹配,属于模糊匹配
//A
public void onClick(View v){
//数据传输
String data = "Hello, xiaozhi";
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
intent.putExtra("extra_data", data);
startActivity(intent);
}
//B
Intent intent = getIntent();
String data = intent.getStringExtra("extra_data");
Toast.makeText(SecondActivity.this, data, Toast.LENGTH_SHORT).show();
Bundle
//A
public void toSecond(View view) {
Intent intent = new Intent(this, Main2Activity.class);
Bundle bundle = new Bundle();
bundle.putString("name", "xiaozhi");
bundle.putInt("age", 24);
intent.putExtras(bundle);
startActivity(intent);
}
//B
Intent intent = getIntent();
String name = intent.getStringExtra("name");
int age = intent.getIntExtra("age", 0);
Toast.makeText(this, "name:" + name + "age:" + age, Toast.LENGTH_SHORT).show();
返回上一层时带数据
//重新启动时可以获取数据 A
Button button8 = (Button) findViewById(R.id.button_8);
button8.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
Intent intent = new Intent(FirstActivity.this, ThirdActivity.class);
startActivityForResult(intent, 1);
}
});
//设置返回数据 B
public void onClick(View v){
Intent intent = new Intent();
intent.putExtra("data_return", "xiaozhi, hi");
setResult(RESULT_OK, intent);
finish();
}
//获取上一个活动返回的数据 A
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
switch (requestCode){
case 1:
if(resultCode == RESULT_OK){
String returnData = data.getStringExtra("data_return");
Toast.makeText(FirstActivity.this, returnData, Toast.LENGTH_SHORT).show();
}
}
}
生命周期
- 运行状态:位于栈顶
- 暂停状态:仍然可见,但不是位于栈顶
- 停止活动:不位于栈顶,也不可见
- 摧毁活动:从返回栈移除,系统回收内存
生存期
- 七个回调方法
- onCreate():活动第一次创建的时候
- onStart():活动由不可见变为可见时
- onResume():活动位于栈顶,处于运行状态,准备和用户交互时
- onPause():系统准备去启动或恢复另一个活动时
- onStop():活动完全不可见时时
- onDestroy():活动在被摧毁之前调用
- onRestart():活动由停止状态变为运行状态之前调用
- 完整生存期:onCreate()到onDestroy(),在onDestroy()中完成释放内存
- 可见生存期:onStart()到onStop(),活动对用户总是可见,onStart()中加载资源,onStop()释放资源
- 前台生存期:onResume()到onPause(),活动总是处于运行状态
- 活动回收A启动B,系统内存不足回收A,按返回键还是会返回A,但是执行的是onRestart,但是如果有数据可能会被丢失,可以重写onSaveInstanceState来保存数据
//保存数据
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onPostCreate(outState);
String tempDate = "hi,xiaozhi";
outState.putString("data_key", tempDate);
}
//恢复数据,onCreate()中
if(savedInstanceState != null){
String tempData = savedInstanceState.getString("data_key");
Toast.makeText(FirstActivity.this, tempData, Toast.LENGTH_SHORT).show();
}
启动模式
可以使用android:launchMode来指定模式
<activity android:name=".MainActivity" android:launchMode="singleTop"></activity>
- standard:默认启动模式,每次启动都会创建一个新的实例,并处于栈顶
- singleTop:如果栈顶是该活动,则不会再创建新的实例
- singleTask:如果返回栈存在该活动,则不会再创建新的实例
- singleInstance:启动一个新的返回栈创建实例,getTaskId()可以获取当前栈的id。活动A、C为标准启动,B为singleInstance启动,A启动B,B启动C,按下back,会直接返回A
知晓活动
新建类BaseActivity继承AppCompatActivity,重写onCreate,再让其他活动基础BaseActivity
public class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("BaseActivity", getClass().getSimpleName());
}
}
一键退出程序
- 新建一个类作为活动管理器
public class ActivityCollector {
public static List<Activity> activities = new ArrayList<>();
public static void addActivity(Activity activity){
activities.add(activity);
}
public static void removeActivity(Activity activity){
activities.remove(activity);
}
public static void finishAll(){
for(Activity activity:activities){
activity.finish();
}
//杀掉当前进程
android.os.Process.killProcess(android.os.Process.myPid());
}
}
- 在BaseActivity类中重写onCreate和onDestroy()
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("BaseActivity", getClass().getSimpleName());
ActivityCollector.addActivity(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
ActivityCollector.removeActivity(this);
}
- 在按钮点击事件调用ActivityCollector.finishAll()即可一键退出
- 可以在摧毁所有活动后再加上杀掉当前进程的代码
启动活动的最佳写法
- 当启动SecondActivity必须传入两个重要的参数时
//在SecondActivity添加actionStart方法
public static void actionStart(Context context, String data1, String data2){
Intent intent = new Intent(context,SecondActivity.class);
intent.putExtra("data1", data1);
intent.putExtra("data2", data2);
context.startActivity(intent);
}
- 方便查看所需参数,调用actionStart即可
SecondActivity.actionStart(FirstActivity.this,"data1","data2");
常用控件
公共属性
- layout_width:宽度,layout_height:高度
- match_parent:和父控件相同
- wrap_content:刚好包含住里面的内容
- visibility:是否可见,可以使用setVisibility()动态修改值
- visible:默认值,可见
- invisible:不可见,但是占用空间
- gone:不可见也不占用空间
- background:背景
- layout_margin:偏移
TextView
<TextView
android:id="@+id/text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textStyle="italic"
android:textColor="#00ff00"
android:textSize="30sp"
android:shadowColor="@color/colorAccent"
android:shadowRadius="3.0"
android:shadowDx="10.0"
android:shadowDy="10.0"
android:text="This is a TextView"
/>
-
textStyle:字体风格,normal(无效果)、italic(斜体)、bold(加粗)
-
gravity:文字对齐方式
-
textColor:字体颜色
-
textSize:字体大小,单位sp(可随系统设置变换),还有dp(只和屏幕尺寸相关)和px(越大越清晰)
-
带阴影的TextView
- shadowColor:设置阴影的颜色,要与shadowRadius一起使用
- shadowRadius:设置阴影的模糊程度,设置为0.1就变成字体颜色了,建议使用3.0
- shadowDx、shadowDy:阴影在水平、竖直方法的偏移
-
滚动文本
<TextView android:id="@+id/tv_one" android:text="文本滚动文本滚动文本滚动文本滚动文本滚动文本滚动文本滚动文本滚动文本滚动文本滚动文本滚动文本滚动" android:layout_width="match_parent" android:layout_height="200dp" android:singleLine="true" android:ellipsize="marquee" android:focusable="true" android:focusableInTouchMode="true" android:marqueeRepeatLimit="marquee_forever"> <requestFocus/> </TextView>
- singleLine:内容单行显示
- ellipsize:在哪里省略文本
- start:省略号显示在开头
- end:省略号显示在结尾
- middle:省略号显示在中间
- marquee:以横向滚动方式显示(需获得当前焦点时)
- focusable:是否可以获取焦点
- focusableInTouchMode:用于控制视图在触摸模式下是否可以聚焦
- marqueeRepeatLimit:字幕动画重复的次数
- -1、marquee_forever:无限次
- 1:一次
- requestFocus:请求焦点
按钮
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button"
android:enabled="false"
android:textAllCaps="false"
android:drawableTop="@drawable/a"
android:drawablePadding="5dp"
android:background="@drawable/btn_selector"
/>
<ImageButton
android:id="@+id/image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/a"
android:scaleType="fitCenter"
/>
-
Button和ImageButton的差异
- Button即可以显示文本也可以显示图片,ImageButton只能显示图片,为避免显示不全scaleType必须为fitCenter
- ImageButton上的图像可按比例缩放,Button通过设置背景的图像会被拉伸变形(fitXY)
- Button只能靠背景显示一张图片,而ImageButton可分别在前景和背景显示图片,从而实现两张图片叠加的效果
-
textAllCaps:false为禁用自动大写转换
-
drawableTop:指定文字上方的图片,除此之外还有drawableBottom、drawableLeft、drawableRight
-
drawablePadding:指定图片与文字的距离
-
enabled:false为禁用
-
selector
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/ic_accessible_black_24dp" android:state_pressed="true" /> <item android:drawable="@drawable/ic_accessibility_black_24dp" /> </selector>
- state_pressed:按下
-
点击事件、长按事件、触摸事件
//点击事件 btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.e(TAG, "onClick: "); } }); //长按事件 btn.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { Log.e(TAG, "onLongClick: "); //如果返回true,则表示消费点击事件 return false; } }); //触摸事件 btn.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Log.e(TAG, "onTouch: " + event.getAction()); //如果返回true,则表示消费点击事件 return false; } }); // 输出 // E/xiaozhi: onTouch: 0 // E/xiaozhi: onTouch: 2 // E/xiaozhi: onTouch: 2 // E/xiaozhi: onLongClick: // E/xiaozhi: onTouch: 1 // E/xiaozhi: onClick:
-
注册监听器
- 匿名类
- 实现接口
public class MainActivity extends AppCompatActivity implements View.OnClickListener{ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button button = (Button)findViewById(R.id.bottom); button.setOnClickListener(this); } //点击 @Override public void onClick(View v) { switch (v.getId()){ case R.id.button: //在此处添加逻辑 break; default: break; } } //长按超过500ms @Override public boolean onLongClick(View v) { if (v.getId() == R.id.button) { //在此处添加逻辑 } return true; } }
文本输入框
<EditText
android:id="@+id/edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="不能为空"
android:textColorHint="#95a1aa"
android:inputType="textPassword"
android:maxLength="2"
/>
- hint:输入框提示
- textColorHint:提示字体的颜色
- inputType:输入类型
- numberDecimal:可以带小数点的浮点格式
- number:0-9
- textPassword:输入的字符会变成星号
- maxLines:输入框最大行数
- maxLength:输入框最大字符数
- 获取输入框内容
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private EditText editText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button)findViewById(R.id.bottom);
editText = (EditText)findViewById(R.id.edit_text);
button.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.button:
String inputText = editText.getText().toString();
Toast.makeText(MainActivity.this, inputText, Toast.LENGTH_SHORT).show();
break;
default:
break;
}
}
}
图片
<ImageView
android:id="@+id/image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="center"
android:src="@drawable/a"
android:maxWidth="200dp"
android:maxHeight="200dp"
android:adjustViewBounds="true"
/>
<!--android:scaleType="center"-->
-
src:图片地址
-
maxWidth:最大宽度
-
maxHeight:最大高度
-
adjustViewBounds:调整View的界限,配合maxWidth、maxHeight实现最大限度的等比缩放
-
scaleType:以FIT_开头的4种,它们的共同点都会对图片进行缩放,以CENTER_开头的3种,它们的共同点是居中显示,图片的中心点会与ImageView的中心点重
- FIT_CENTER,默认,图片会被等比缩放到能够填充控件大小,并居中展示
- FIT_START,图片等比缩放到控件大小,并放置在控件的上边或左边展示,多余的上/右半部份留白
- FIT_END,图片等比缩放到控件大小,并放置在控件的下边或右边展示,多余的下/右半部份留白
- FIT_XY,图片缩放到控件大小,完全填充控件大小展示,非等比缩放
- CENTER,不使用缩放,如果图片的大小小于控件的宽高,那么图片会被居中显示,只显示控件尺寸
- CENTER_CROP,图片会被等比缩放直到完全填充整个ImageView,裁剪后并居中显示
- CENTER_INSIDE,图片将被等比缩放到能够完整展示在ImageView中并居中,如果图片大小小于控件大小,那么就直接居中展示该图片
- MATRIX,该模式需要与ImageView.setImageMatrix(Matrix matrix) 配合使用
imageView.setScaleType(ImageView.ScaleType.MATRIX); //设置为矩阵模式 Matrix matrix = new Matrix(); //创建一个单位矩阵 matrix.setTranslate(100, 100); //平移x和y各100单位 matrix.preRotate(30); //顺时针旋转30度 imageView.setImageMatrix(matrix); //设置并应用矩阵
-
动态修改图片地址
public class MainActivity extends BaseActivity implements View.OnClickListener {
private ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button1 = (Button)findViewById(R.id.button_1);
imageView = (ImageView)findViewById(R.id.image_view);
button1.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.button_1:
imageView.setImageResource(R.drawable.b);
break;
default:
break;
}
}
}
进度条
<ProgressBar
android:id="@+id/progress_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?android:attr/progressBarStyleHorizontal"
android:max="100"
/>
- 默认为圆形转圈动画
- progressBarStyleHorizontal:条形进度条
- max:进度条最大值,可以动态修改进度条进度
- indeterminate:设置为true可隐藏进度值
int progress = progressBar.getProgress();
progress = progress +10;
progressBar.setProgress(progress);
通知
- Notification与NotificationManager
- NotificationManager类是一个通知管理器类,这个对象是由对象维护的服务,是以单例模式的方式获得,所以一般并不直接实例化这个对象。在Activity中,可以使用Activity.getSystemService(Context.NOTIFICATION_SERVICE)方法获取NotificationManager对象,Activity.getSystemService(String)方法可以通过Android系统级服务的句柄,返回对应的对象。
- 使用NotificationCompat类的Builder构造器来创建Notification对象,可以保证程序在所有的版本上都能正常工作。Android 8.0新增了通知渠道这个概念,如果没有设置,则通知无法在Android 8.0的机器上显示。
public class MainActivity extends AppCompatActivity {
private static final String TAG = "xiaozhi";
private NotificationManager manager;
private Notification notification;
private PendingIntent pendingIntent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel("xiaozhi", "聊天消息", NotificationManager.IMPORTANCE_HIGH);
manager.createNotificationChannel(channel);
}
Intent intent = new Intent(this, Main2Activity.class);
pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
}
public void sentNotification(View view) {
if (!NotificationManagerCompat.from(this).areNotificationsEnabled()) {
//未打开通知
AlertDialog alertDialog = new AlertDialog.Builder(this)
.setTitle("提示")
.setMessage("请在“通知”中打开通知权限")
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
})
.setPositiveButton("去设置", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
Intent intent = new Intent();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS");
intent.putExtra("android.provider.extra.APP_PACKAGE", MainActivity.this.getPackageName());
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { //5.0
intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS");
intent.putExtra("app_package", MainActivity.this.getPackageName());
intent.putExtra("app_uid", MainActivity.this.getApplicationInfo().uid);
startActivity(intent);
} else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) { //4.4
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setData(Uri.parse("package:" + MainActivity.this.getPackageName()));
} else if (Build.VERSION.SDK_INT >= 15) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.setData(Uri.fromParts("package", MainActivity.this.getPackageName(), null));
}
startActivity(intent);
}
})
.create();
alertDialog.show();
alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE).setTextColor(Color.BLACK);
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(Color.BLACK);
}
notification = new NotificationCompat.Builder(this, "xiaozhi")
.setContentTitle("官方通知")
.setContentText("小志,你好")
.setSmallIcon(R.drawable.ic_account_circle_black_24dp)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.p1))
.setColor(Color.parseColor("#ff0000"))
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.build();
manager.notify(1, notification);
}
//取消通知
public void cancelNotification(View view) {
manager.cancel(1);
}
}
导航栏
- 自定义导航栏:修改style.xml样式
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
- 自定义导航栏样式
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/tb"
android:background="#ffff00"
app:navigationIcon="@drawable/ic_arrow_back_black_24dp"
app:titleTextColor="#ff0000"
app:titleMarginStart="90dp"
app:title="标题"
app:subtitle="子标题"
app:subtitleTextColor="#00ffff"
app:logo="@mipmap/ic_launcher"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" />
<androidx.appcompat.widget.Toolbar
android:background="#ffff00"
app:navigationIcon="@drawable/ic_arrow_back_black_24dp"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="标题"
android:layout_gravity="center"/>
</androidx.appcompat.widget.Toolbar>
</LinearLayout>
- 监听返回事件
public class MainActivity extends AppCompatActivity {
private static final String TAG = "xiaozhi";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar tb = findViewById(R.id.tb);
tb.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e(TAG, "onClick: 点击返回");
}
});
}
}
弹窗
- 普通弹窗
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.button_1:
AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this);
dialog.setTitle("提示");
dialog.setMessage("确定要删除吗?");
//setCancelable:是否可以返回,false表示不可以,默认true
dialog.setCancelable(false);
dialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(MainActivity.this, "已删除", Toast.LENGTH_SHORT).show();
}
});
dialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(MainActivity.this, "已取消", Toast.LENGTH_SHORT).show();
}
});
dialog.show();
break;
default:
break;
}
}
-
popupWindow
- 自定义布局popup_view.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/p1" android:orientation="vertical"> <Button android:id="@+id/btn1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="按钮1" android:textSize="18sp" android:padding="5dp"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="按钮2" android:textSize="18sp" android:padding="5dp"/> </LinearLayout>
- 控制弹窗的位置以及按钮点击事件
public void myClick(View view) { View popupView = getLayoutInflater().inflate(R.layout.popup_view, null); final PopupWindow popupWindow = new PopupWindow(popupView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true); Button btn1 = popupView.findViewById(R.id.btn1); btn1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this, "点击了btn1", Toast.LENGTH_SHORT).show(); popupWindow.dismiss(); } }); popupWindow.showAsDropDown(view); }
复选框
<CheckBox
android:id="@+id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="红色"
android:checked="true"/>
- checked:是否默认选择
单选框
<RadioGroup
android:id="@+id/radio_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<RadioButton
android:id="@+id/radiobutton1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="男" />
<RadioButton
android:id="@+id/radiobutton2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="女" />
</RadioGroup>
- 单选按钮要声明在RadioGroup内
开关按钮
<Switch
android:id="@+id/switch1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
内置浏览器
<WebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
常用布局
LinearLayout
线性布局
- orientation:排列方向
- vertical:垂直排列,高度不能设置为match_parent,只有水平方向对齐才会生效
- horizontal:水平排列,宽度不能设置为match_parent,只有垂直方向对齐才会生效
- layout_gravity:对齐方式
- layout_weight:按比例方式指定控件大小,layout_width需设置为0dp(规范)
- divider:分割线图片
- showDividers:是否显示
- dividerPadding:分割线左右边距多少
RelativeLayout
相对布局
- 以父控件为参照物,属性为true则生效
- layout_alignParentLeft:左
- layout_alignParentTop:上
- layout_alignParentRight:右
- layout_alignParentBottom:下
- layout_centerInParent:中
- 以button_2为参照物,button_2必须已定义且在上方
- layout_above="@id/button_2":位于button_2上方
- layout_below="@id/button_2":位于button_2下方
- layout_toLeftOf="@id/button_2":位于button_2左侧
- layout_layout_toRightOf="@id/button_2":位于button_2右侧
- layout_alignLeft:左对齐
- layout_alignRight:右对齐
- layout_alignTop:上对齐
- layout_alignBotton:下对齐
FrameLayout
帧布局,如果位置相同,后添加的会遮住先添加的
TableLayout
表格布局
- collapseColumns(隐藏列),可指定多列
<TableLayout
android:id="@+id/TableLayout1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:collapseColumns="1,4" >
<TableRow>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="one" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="two" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="three" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="four" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="five" />
</TableRow>
</TableLayout>
- stretchColumns(拉伸列),可指定一列让该列填满这一行所有的剩余空间
<TableLayout
android:id="@+id/TableLayout2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:stretchColumns="1" >
<TableRow>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="one" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="two" />
</TableRow>
</TableLayout>
- shrinkColumns(收缩列),可指定一列为可收缩列
<TableLayout
android:id="@+id/TableLayout3"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:shrinkColumns="1" >
<TableRow>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="one" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="two" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="three" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="four" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="fivefivefive" />
</TableRow>
</TableLayout>
- 子控件常用属性:
- android:layout_column:在第几列显示
- android:layout_span:占据列数
GridLayout
网格布局
- rowCount:设置网格布局行数
- columnCount:设置网格布局列数
- 子控件常用属性:
- android:layout_column:第几列
- android:layout_span:占据列数
- layout_row:设置组件位于行数
- layout_column:设置该组件位于列数
- layout_rowSpan:设置某个组件纵向横跨行数
- layout_columnSpan:设置某个组件横向横跨列数
- layout_columnWeight:分配列剩余权重
- layout_rowWeight:分配行剩余权重
ViewPager2
- 导入依赖
implementation 'androidx.viewpager2:viewpager2:1.0.0'
滚动视图
滚动视图节点下面必须且只能挂着一个子布局节点。有时ScrollView内容不够,又想让它充满屏幕,可以设置下列属性
android:layout_height="match_parent"
android:fillViewport= "true"
- 横向滚动 HorizontalScrollView
<HorizontalScrollView
android:layout_width="wrap_content"
android:layout_height="200dp">
<!-- 水平方向的线性布局,两个子视图的颜色分别为青色和黄色 -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal">
<View
android:layout_width="300dp"
android:layout_height="match_parent"
android:background="#aaffff" />
<View
android:layout_width="300dp"
android:layout_height="match_parent"
android:background="#ffff00" />
</LinearLayout>
</HorizontalScrollView>
- 纵向滚动 ScrollView
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- 垂直方向的线性布局,两个子视图的颜色分别为绿色和橙色 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="400dp"
android:background="#00ff00" />
<View
android:layout_width="match_parent"
android:layout_height="400dp"
android:background="#ffffaa" />
</LinearLayout>
</ScrollView>
自定义布局
- 隐藏默认标题栏
ActionBar actionBar = getSupportActionBar();
if(actionBar != null){
actionBar.hide();
}
- 引入布局:
<include layout="@layout/title"/>
- 动态加载,from()可以构建LayoutInflater对象,调用inflate()动态加载布局文件,第一个参数是要加载布局文件的id,第二个参数是给加载好的布局在添加一个父布局
public TitleLayout(Context context, AttributeSet arrts) {
super(context, arrts);
LayoutInflater.from(context).inflate(R.layout.activity_main, this);
}
ListView
public class MainActivity extends AppCompatActivity {
private String[] data = {"item01","item02","item03","item04","item05","item06","item07","item08",
"item09","item10","item11","item12","item13","item14","item15","item16","item17","item18"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, data);
ListView listView = findViewById(R.id.list_view);
listView.setAdapter(adapter);
}
}
布局文件
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
- getView()这个方法会在每个子项滚到屏幕时调用
- LayoutInflater.inflate加载传入的布局
- 优化
- convertView()缓存布局
- ViewHolder缓存实例
滚动控件
RecycleView
- 在app/build.gradle添加依赖:implementation 'androidx.recyclerview:recyclerview:1.1.0'
- 适配器
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {
private List<Fruit> mFruitList;
static class ViewHolder extends RecyclerView.ViewHolder {
TextView fruitName;
public ViewHolder(View view) {
super(view);
fruitName = view.findViewById(R.id.fruit_name);
}
}
public FruitAdapter(List<Fruit> fruitList) {
mFruitList = fruitList;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item, parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Fruit fruit = mFruitList.get(position);
holder.fruitName.setText(fruit.getName());
}
@Override
public int getItemCount() {
re turn mFruitList.size();
}
}
- 布局文件
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
- 其他布局
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了