开发Android App
B站的视频笔记
创建项目
可以看项目页面什么样子,可在右侧属性修改页面显示内容
通过代码修改页面显示内容
编译项目
make一下多了一个build 目录
添加模拟器
控件
TextView
基本属性
规范写法,控件中的文字和颜色要写入 src/main/res/values对应的colors和strings文件中
colors.xml,也可以直接写入
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
</resources>
strings.xml
<resources>
<string name="app_name">Android93</string>
<string name="tv_one">init</string>
</resources>
activity_main.xml
<!--
TextView 文本组件
width/height: wrap_content 根据宽度使用,最大不超过父容器
match_parent 适配父容器
具体数字
id: 组件id,通过id可用查找到控件 TextView tv_one = findViewById(R.id.tv_one);
textColor: 文字颜色#00000000(8位) 前2位表示透明度
text: 文本内容
textStyle: 字体风格,normal(无效果) bold(加粗) italic(斜体)
textSize: 字体大小,单位一般sp
background: 背景颜色,可以是图片
gravity: 控件内内容的对齐方式,TextView是文字,imageView 是图片
android:shadowColor 阴影颜色,需要和shadowRadius 一起使用
android:shadowRadius 阴影模糊程度,建议:3.0
android:shadowDx/ android:shadowDy :阴影在x,y方向的偏移
-->
<TextView
android:layout_width="200dp"
android:layout_height="200dp"
android:text="@string/tv_one"
android:textColor="@color/purple_200"
android:textSize="30sp"
android:textStyle="bold"
android:background="@color/teal_200"
android:gravity="center"
android:shadowColor="@color/black"
android:shadowRadius="3"
android:shadowDx="15"
android:shadowDy="2"
android:id="@+id/tv_one"></TextView>
跑马灯效果
<!--
android:ellipsize: 文字省略的方式,跑马灯效果是设置为:"marquee"
android:singleLine: 单行
实现跑马灯效果需要聚焦:
android:focusable: 是否可以获取焦点
android:focusableInTouchMode="true" 视图在触摸模式下,是否可以聚焦
android:marqueeRepeatLimit="marquee_forever" 跑马灯循环次数
//方法一: 可点击(点击后,跑马灯效果)
android:clickable="true"
//目的:进入后,就自动运行
//方法二:
新建一个class MyTextView 继承 TextView ,重写isFocused 方法,直接返回 true
控件使用的地方 TextView 更改为MyTextView
// 方法三
<requestFocus/>
-->
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="@string/tv_one"
android:textColor="@color/purple_200"
android:textSize="10sp"
android:textStyle="bold"
android:background="@color/teal_200"
android:gravity="center"
android:shadowColor="@color/white"
android:shadowRadius="3"
android:shadowDx="5"
android:shadowDy="2"
android:singleLine="true"
android:focusable="true"
android:focusableInTouchMode="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:id="@+id/tv_one">
<requestFocus/>
</TextView>
方法二:
package com.example.android93;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.TextView;
import androidx.annotation.Nullable;
public class MyTextView extends androidx.appcompat.widget.AppCompatTextView {
public MyTextView(Context context) {
super(context);
}
public MyTextView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public MyTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean isFocused() {
return true;
}
}
Button
StateListDrawable
StateListDrawable可以根据不同的状态,设置不同的图片效果,将button的背景图,颜色等设置为drawable或color资源即可实现,按钮不同状态的颜色背景更换
- drawable: 引用的是drawable位图
- state_focused: 获取焦点
- state_pressed: 按下
- state_enable: 是否可用
- state_selected: 是否被选择,针对有滚轮的情况
- state_checked: 是否给勾选,eg:checkbox
- state_window_focused: 是否获得窗口焦点
- state_active: 是否是获得状态 eg:slidingTab
- …更多查看该属性
前景色位于最上层,设置后,遮盖其他效果( android:foreground=“#ff0000ff”)
<Button
android:text="按钮"
android:background="@drawable/btn_selector"
android:backgroundTint="@color/btn_color_selector"
android:layout_width="100dp"
android:layout_height="100dp"></Button>
新建button的drawableResourceFile
加载几张系统自带图片,也可从网上下载
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 按钮按下-->
<item android:drawable="@drawable/ic_baseline_account_balance_24" android:state_pressed="true"></item>
<!-- 不设置:默认状态-->
<item android:drawable="@drawable/ic_baseline_account_box_24" ></item>
</selector>
新建color的ColorResourceFile
需在res下新建color文件夹
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#ffff0000" android:state_pressed="true"></item>
<item android:color="#ff00ff00"></item>
</selector>
btn 点击事件
Cannot resolve symbol ‘@+id/search’
给按钮添加id的时候一致报错:解决方法(clean 一下就可以了):
Cannot resolve symbol ‘TAG’
将日志消息打印到控制台时用作标记的字符串。
将以下行添加到类的顶部中:
private static final String TAG = MainActivity.class.getSimpleName();
事件
<Button
android:text="按钮"
android:id="@+id/btn"
android:background="@drawable/btn_selector"
android:backgroundTint="@color/btn_color_selector"
android:layout_width="100dp"
android:layout_height="100dp"></Button>
MainActivity.java
package com.example.android93;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
public static final String TAG = "YOUR-TAG-NAME";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = findViewById(R.id.btn);
// 点击事件
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.e(TAG, "onClick: ");
}
});
// 长按事件 返回true 则不会调用click事件
button.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
Log.e(TAG, "onLongClick: " );
return false;
}
});
// 触摸事件 ontouch分为多种,点击的时候,先触发ontouch事件,如果返回为true,则事件不再
// 传递给click、longclick
button.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
Log.e(TAG, "onTouch: "+motionEvent.getAction());
return false;
}
});
}
}
EditText 输入框
<!--
android:hint="请输入用户名" 输入提示
android:textColorHint="#95a1aa" 提示颜色
android:inputType="text" 输入框输入文字类型
android:drawableXXXX 在指定方向添加图片
android:padding/android:paddingLeft 设置内容和边框的间距
android:background 背景色
-->
<EditText
android:layout_width="200dp"
android:layout_height="100dp"
android:id="@+id/input"
android:hint="请输入用户名"
android:textColorHint="#95a1aa"
android:drawableLeft="@drawable/ic_baseline_account_box_24"
android:paddingLeft="20dp"
android:background="@color/purple_500"
android:inputType="text"></EditText>
内容的获取(可放在按钮点击事件内)
EditText editText = findViewById(R.id.input);
editText.getText().toString();
imageView
android:scaleType
放大缩小的方式
<!-- 不改变原图的大小,从左上角开始绘制,超出部分裁剪-->
<enum name="matrix" value="0" />
<!-- 缩放图片,适应ImageView -->
<enum name="fitXY" value="1" />
<!-- 保持宽高比,缩放图片,至大的一边等于容器边长,放在左上角 -->
<enum name="fitStart" value="2" />
<!--保持宽高比,缩放图片,至大的一边等于容器边长,放在中间 -->
<enum name="fitCenter" value="3" />
<!-- 保持宽高比,缩放图片,至大的一边等于容器边长,放在右下角 -->
<enum name="fitEnd" value="4" />
<!-- 保持原图大小,把图片放在中间,超出部分裁剪-->
<enum name="center" value="5" />
<!--保持宽高比缩放图片,至完全覆盖Imageview -->
<enum name="centerCrop" value="6" />
<!-- 保持宽高比缩放图片,至imageView显示图片-->
<enum name="centerInside" value="7" />
固定宽高布局
设置宽高,图片会根据scaleType去适应容器
android:layout_width=“200dp”
android:layout_height=“200dp”
<ImageView
android:layout_width="200dp"
android:layout_height="200dp"
android:scaleType="fitXY"
android:src="@drawable/day"></ImageView>
图片自适应布局
不能少了 android:adjustViewBounds="true"
``
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxHeight="200dp"
android:maxWidth="200dp"
android:scaleType="fitXY"
android:src="@drawable/day"
android:adjustViewBounds="true"></ImageView>
ProgressBar
<!--
不设置下面参数,默认是圆的loading
android:layout_width="100dp"
android:layout_height="50dp"
android:max="100" 进度条的最大值
android:progress="60" 进度条已经完成的进度值
android:indeterminate="true" 设置true,则进度条不精确显示进度,从左盗用动态
style="?android:attr/progressBarStyleHorizontal" 系统默认样式的进度条
-->
<ProgressBar
android:id="@+id/pb"
android:layout_width="100dp"
android:layout_height="50dp"
android:max="100"
android:progress="50"
android:indeterminate="true"
style="?android:attr/progressBarStyleHorizontal"
></ProgressBar>
<Button
android:layout_width="wrap_content"
android:onClick="btnClick"
android:layout_height="wrap_content"
android:text="显示隐藏进度条+1"></Button>
点击事件
public void btnClick(View view) {
// 隐藏了就显示
// if(pb.getVisibility()==View.GONE){
// pb.setVisibility(View.VISIBLE);
// }else{
// pb.setVisibility(View.GONE);
// }
int progress = pb.getProgress();
progress +=5;
pb.setProgress(progress);
}
Notification
要实现一个通知,需要Notification和NotificationManage
NotificationManage 通知管理类,有系统提供,以单例方式获得,所以一般不直接实例化,在Activity中,可以使用``方法获取
使用Builder构造器来创建Notificatin对象
在页面添加2个按钮
// activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<Button
android:layout_width="wrap_content"
android:onClick="sendNotice"
android:layout_height="wrap_content"
android:text="发送通知"></Button>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="cancelNotice"
android:text="取消通知"></Button>
</LinearLayout>
MainActivity.java
package com.example.android93;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.NotificationCompat;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
public static final String TAG = MainActivity.class.getName();
private NotificationManager manager;
private Notification notification;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// 通知对象 Andorid 8.0 引入了通知渠道,可以为每种要现实的通知创建渠道
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
// id 需要和 notification 中的channelId 一致 name 字符串,展示使用 通知的重要级别
// IMPORTANCE_HIGH 开启通知,弹出,发出提示音、状态栏显示
// IMPORTANCE_NONE 关闭通知
// 更多看文档
NotificationChannel notificationChannel = new NotificationChannel("test", "测试通知", NotificationManager.IMPORTANCE_HIGH);
manager.createNotificationChannel(notificationChannel);
}
Intent intent = new Intent(this,MainActivity2.class);
PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE );
// 通知
notification = new NotificationCompat.Builder(this, "test")
.setContentTitle("官方通知") //通知标题
.setContentText("世界那么大,不出去看看吗?") //通知内容
.setSmallIcon(R.drawable.ic_baseline_account_balance_24)
// icon int 不能直接用图片 android5.0 k开始,图标知恩阁使用alpha图层,不包含RGB图层 不能带压缩
.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.drawable.day)) // 右侧大图片
.setColor(Color.parseColor("#0000ff")) // .setColor(Color.argb(0,255,9,8)) // 设置小图标的颜色
.setContentIntent(pIntent) // 设置跳转意图,eg:点击后跳转App 页面
.setAutoCancel(true) // 点击后自动取消
.build();
}
public void cancelNotice(View view) {
manager.cancel('1');
}
public void sendNotice(View view) {
// 可自定义
manager.notify('1',notification);
}
}
新建activity页面MainActivity2 点击通知后跳转的页面
Toolbar(导航)
系统自带的为actionBar
使用toolbar 更改主题
使用方法:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/tb"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#ffff00"
app:logo="@mipmap/ic_launcher"
app:navigationIcon="@drawable/ic_baseline_arrow_back_24"
app:subtitle="small title"
app:subtitleTextColor="@color/teal_200"
app:title="标题"
app:titleMarginStart="90dp"
app:titleTextColor="@color/purple_500"></androidx.appcompat.widget.Toolbar>
<androidx.appcompat.widget.Toolbar
android:id="@+id/tb2"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"></androidx.appcompat.widget.Toolbar>
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:background="@color/purple_200"
app:navigationIcon="@drawable/ic_baseline_arrow_back_24"
android:layout_height="?attr/actionBarSize">
<TextView
android:layout_width="wrap_content"
android:layout_gravity="center"
android:text="标题放中间"
android:layout_height="wrap_content"></TextView>
</androidx.appcompat.widget.Toolbar>
</LinearLayout>
MainActivity.java
package com.example.toolbar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
public class MainActivity extends AppCompatActivity {
@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: toolbar click");
}
});
Toolbar tb2 = findViewById(R.id.tb2);
tb2.setNavigationIcon(R.drawable.ic_baseline_arrow_back_24);
tb2.setTitle("第二个toolbar");
tb2.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e("TAG", "onClick: 第二个toolbar click");
}
});
}
}
AlertDialog
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="showDialog"
android:text="显示弹框"></Button>
</LinearLayout>
dialog_view.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="horizontal"
android:background="@color/purple_200"
xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher"></ImageView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="自定义view"></TextView>
</LinearLayout>
MainActivity.java
package com.example.alertdialog;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void showDialog(View view) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
View inflate = getLayoutInflater().inflate(R.layout.dialog_view, null);
// 前面的可以随便放,create、show 需要放后面,返回值不一样
builder.setTitle("我是对话框")
.setIcon(R.mipmap.ic_launcher)
.setMessage("今天你加班了吗?")
.setView(inflate)
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Log.e("TAG", "onClick: 确定");
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Log.e("TAG", "onClick: 取消" );
}
})
.setNeutralButton("中间", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Log.e("TAG", "onClick: 中间按钮");
}
})
.create()
.show();
}
}