**
项目一
**
第三章 Android------- UI开发的控件和布局(实验三)
D4-D2-D6-AF-EE-3A (2026)
添加链接描述
转载链接:https://blog.csdn.net/qq_53063025/article/details/111145829
实验目的
在Android Studio上如何实现UI开发的控件和布局,开发的项目名称是UIWIidgetTest,如何用编译的代码来实现简单的控件和布局。
软件
Android Studio
实验步骤
1. TextView****在界面上显示一段文本信息
2. Button在界面上显示一个按钮
3**.EditText可编辑的文本,允许用户在控件里输入和编辑**
4**. ImageView在界面上显示图片**
- ProgressBar在界面上显示一个进度条
6**.AlertDialog在当前界面弹出一个对话框,不同于上面的,这个是在程序中写的**
7.ProgressDialog在当前界面弹出一个有进度条的对话框,也是在程序中完成
- 程序转换字符串
9.最后综合得出
10.在虚拟机上运行的效果
11**.在手机运行效果**
- 线性布局垂直方向布局vertical
13.运行得效果
14.horizontal垂直方向布局
- 运行效果
16.layout_width水平宽度布局
17.运行效果
18.ListView的简单用法
19.public class FruitAdapter
20.fruit
21.LinearLayout
22.FruitAapter
23.在MainActivity中编写,初始化水果数据
- 最后运行效果
项目二
第六章 数据存储全方案
82-30-49-6B-2F-0D (2017 2004)
添加链接描述
一.文件储存
建立一个mylnnerdata后,activity_main_xml代码如下
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="数据的内部存储"
android:textSize="22sp" />
<Button
android:id="@+id/but_save"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="存储数据"
android:textSize="22sp"/>
<Button
android:id="@+id/but_read"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="读取数据"
android:textSize="22sp"/>
MainActivity代码如下
package com.example.mylnnerdata;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
/**
-
主界面的逻辑代码
*/
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button but_save,but_read;//保持与读取按钮
private Object FileInputStream;
private String fileName = “mydb.text”;//文件名称
// String strNr = “HelloWorld”;//要保存的数据@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);but_save = findViewById(R.id.but_save); but_read = findViewById(R.id.but_read); but_save.setOnClickListener(this); but_read.setOnClickListener(this);
}
//点击处理方法
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.but_save://保存数据
savaData();
break;
case R.id.but_read:
readData();
break;
}}
//保存数据的方法
private void savaData() {
// String fileName = “mydb.text”;//文件名称
String strNr = “HelloWorld,I’m coming”;//要保存的数据
FileOutputStream fos = null;try { fos = openFileOutput(fileName,MODE_PRIVATE); fos.write(strNr.getBytes());//将数据写入文件中去 Toast.makeText(this, "保存数据成功", Toast.LENGTH_SHORT).show(); } catch (Exception e) { e.printStackTrace(); }finally { try { if (fos!=null){ fos.close(); } }catch (Exception ex){ ex.printStackTrace(); } }
}
//读取数据的方法
private void readData() {
String strNr = “”;//要读取的内容变量
// FileInputStream = null;
InputStream fis = null;
try {
fis = openFileInput(fileName);//获取输入流对象
byte[] buffer = new byte[fis.available()];//创建读取的缓冲对象
fis.read(buffer); //将文件内容读取到缓冲区中去
strNr = new String(buffer); //转换成字符串
Toast.makeText(this, strNr, Toast.LENGTH_SHORT).show();//显示}catch (Exception ex){ ex.printStackTrace(); }finally { try { if (fis!=null) { } else { fis.close(); } }catch (Exception ex){ ex.printStackTrace(); } }
}
}
点击运行后结果如下(手机页面)
SharedPreferences储存
建立一个mylnnerdata后,activity_main_xml代码如下
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginTop="15dp"
android:background="#ffffff">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="用户名"
android:textSize="20dp" />
<EditText
android:id="@+id/et_uname"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
android:hint="请输入用户名"
android:background="@null"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginTop="15dp"
android:background="#ffffff">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="密 码:"
android:textSize="20dp" />
<EditText
android:id="@+id/et_upass"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
android:inputType="textPassword"
android:hint="请输入密码"
android:background="@null"/>
</LinearLayout>
<Button
android:id="@+id/btn_login"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="登录"
android:textSize="20sp"/>
首先建立好myspdata下再建立SPDataUtils和Userinfo
MainActivity代码如下
package com.example.myspdata;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
/**
- 主界面逻辑代码
*/
public class MainActivity extends AppCompatActivity implements OnClickListener {
private Button btn_login;
private EditText et_uname,et_upass;//用户名与密码控件
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();//初始化控件
initData();//加载初始化的数据
}
//初始化控件
private void initView(){
btn_login = findViewById(R.id.btn_login);
et_uname = findViewById(R.id.et_uname);
et_upass = findViewById(R.id.et_upass);
btn_login.setOnClickListener(this);
}
//初始化界面数据
private void initData(){
Userinfo user = SPDataUtils.getUserionfo(this);
if (user!=null && !TextUtils.isEmpty(user.getUname())){
et_uname.setText(user.getUname());
et_upass.setText(user.getUpass());
}
}
//点击事件处理
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_login://登录
chkAndSaveData();
break;
}
}
/**
* 检查登录数据并精选保存
*/
private void chkAndSaveData(){
String uname = et_uname.getText().toString().trim();
String upass = et_upass.getText().toString().trim();
if (TextUtils.isEmpty(uname)){
showMsg("请输入用户名信息");
}else if (TextUtils.isEmpty(upass)){
showMsg("请输入密码信息");
}else {
boolean flag = SPDataUtils.saveUserInfo(this,uname,upass);
if (flag){
showMsg("保存数据成功");
}else {
showMsg("保存数据失败");
}
}
}
//显示信息的方法
private void showMsg(String msg){
Toast.makeText(this,msg,Toast.LENGTH_SHORT).show();
}
}
SPDataUtils代码如下
package com.example.myspdata;
import android.content.Context;
import android.content.SharedPreferences;
/**
-
使用sharePreferences实现数据的存取的工具类
*/
public class SPDataUtils {
private static final String mFileName = “mydata”;//文件名称/**
- 保存用户信息
- @param context 上下文件信息
- @param uname 用户名
- @param upass 密码
- @return boolean 结果
*/
static boolean saveUserInfo(Context context, String uname, String upass){
boolean flag = false;
SharedPreferences sp = context.getSharedPreferences(mFileName,Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putString(“uname”,uname);
editor.putString(“upass”,upass);
editor.commit();
flag = true;
return flag;
}/**
-
获取用户信息的方法
-
@param context 调用的上下文
-
@return 返回Userinfo 的实例
*/
public static Userinfo getUserionfo(Context context){
Userinfo user = null;
SharedPreferences sp = context.getSharedPreferences(mFileName,Context.MODE_PRIVATE);
String uname = sp.getString(“uname”, null);
String upass = sp.getString(“upass”, null);user = new Userinfo();
user.setUname(uname);
user.setUpass(upass);
return user;
}
}
Userinfo代码如下
package com.example.myspdata;
/**
-
用户信息实体类
*/
public class Userinfo {
private String uname;
private String upass;public Userinfo() {
}public Userinfo(String uname, String upass) {
this.uname = uname;
this.upass = upass;
}public String getUname() {
return uname;
}public void setUname(String uname) {
this.uname = uname;
}public String getUpass() {
return upass;
}public void setUpass(String upass) {
this.upass = upass;
}
}
结果如下(手机上)
项目三
第七章
跨程序共享数据——实现拨打电话与查看联系人
添加链接描述
F8-A2-D6-D5-82-7B(2020)
文章目录
第一章 程序运行时申请权限
第二章 拨打电话“10086”
第三章 读取系统联系人
前言
本次我们主要学习跨程序实现共享数据,在模拟机上运行出可以实现拨打电话,实现查看联系人
一、程序运行时申请权限
android的权限机制并不是什么新鲜事物,从系统的第一个版本就已经存在了。首先新建一个RuntimePermission Test项目,我们就在这个项目的基础上来学习运行时权限的使用方法。这里我们使用CALL-PHONE这个权限来讲解,CALL-PHONE这个权限时编写拨打电话功能的时候需要声明的,因为拨打电话会涉及用户手机资费问题,因而被列为了危险权限。新建好项目后我们修改activity_main.xml布局文件,如下;
我们在布局文件中只是定义了一个按钮,当点击按钮时就去触发拨打电话的逻辑。接着修改MainActivity中的代码,如下;
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201213191751158.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzUzMDY2MTcx,size_16,color_FFFFFF,t_70
接下来修改AndroidManifest.xml文件,在其中声明如下权限:
二、 拨打电话“10086”
上面我们已经把拨打电话权限打开,这样拨打电话的功能实现了,并且在低于Android6.0系统的手机上都是可以正常运行的,但是如果在6.0或者更高版本系统的手机运行,点击Make Call按钮就没有任何效果,这是我们在继续修改MainActivity中的代码,如下;
现在重新点击运行一下程序,点击MakeCall 按钮,如下;
可以把”10086“电话换成其他号码也可以实现的哟!
三、 读取系统联系人
由于我们一直使用的都是模拟器,电话簿里面没有联系人存在,所以现在需要自己手动添加几个,以便一会儿进行读取,打开电话簿程序,如下;
可以看到目前没有联系人,我们可以通过点击”+“号添加联系人,以下我添加了两个联系人,如下;
准备工作做好后,现在新建一个项目,还是先来布局文件,修改activity_xml中的代码,如下;
接着修改MainActivity中的代码,如下;
记得还要修改联系人的权限,修改AndroidManifest.xml中的代码,如下;
代码改完后就可以点击运行了,运行结果如下;
总结
通过这次学习实现了跨程序共享数据,拨打电话,查看联系人,如何打开权限,也是不小的收获。
项目四
第八章简单运用手机多媒体
简单运用手机多媒体 F8-94-C2-44-C2-AD(2025)
文章目录
一、调用摄像头和相册
1.调用摄像头拍照
在activity_main.xml文件,添加一个Button用于打开摄像头进行拍照,添加ImageView用于将图片显示出来。
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/take_photo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="take photo"/>
<ImageView
android:id="@+id/picture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"/>
</LinearLayout>
MainActivity文件中代码
public class MainActivity extends AppCompatActivity {
public static final int TAKE_PHOTO = 1;
private ImageView picture;
//图片本地的真实路径
private Uri imageUri;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button takePhoto = (Button) findViewById(R.id.take_photo);
picture = (ImageView) findViewById(R.id.picture);
takePhoto.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//用于存放拍下的照片
File outputImage = new File(getExternalCacheDir(), "output_image.jpg");
try {
if(outputImage.exists()){
outputImage.delete();
}
outputImage.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
if(Build.VERSION.SDK_INT >= 24){
//File对象转换为Uri标识对象
imageUri = FileProvider.getUriForFile(MainActivity.this, "com.launcher.cameraalbumtest.fileprovider", outputImage);
}else{
//指定图片的输出地址
imageUri = Uri.fromFile(outputImage);
}
//隐式Intent,启动相机程序
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, TAKE_PHOTO);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode){
case TAKE_PHOTO:
if(resultCode == RESULT_OK){
try {
//拍照成功后显示图片
Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
picture.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
break;
default:
break;
}
}
}
应用关联缓存目录:
SD卡中专门用于存放当前应用缓存数据的位置,调用getExternalCacheDir()方法可以得到这个目录,具体路径:/sdcard/Android/data/<package name>/cache。
Android 6.0以后读写SD卡被列为危险权限,如果将图片存放到其他目录要进行运行时权限处理,使用应用关联缓存目录可以跳过这一步。
Android 7.0以后,直接使用本地真实路径的Uri被认为是不安全的,会抛出FileUriExposedException异常,而使用FileProvider是一种特殊的内容提供器,它使用了和内容提供器类似的机制对数据进行保护,可以选择性的封装过的Uri共享给外部,从而提高应用的安全性。
2.从相册中选择照片
布局文件,放一个Button和一个ImageView,Button用来启动拍照图片并截图,ImageView用来显示截图后的照片,activity_main.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:orientation="vertical">
<Button
android:id="@+id/btn_photo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Take Photo" />
<Button
android:id="@+id/btn_album"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Choose from Album" />
<ImageView
android:id="@+id/img_photo"
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_gravity="center_horizontal" />
</LinearLayout>
MainActivity.java代码:
package com.test.photo;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
//import com.test.R;
import androidx.core.content.FileProvider;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
* Created by Administrator on 2016/5/4 0004.
*/
public class MainActivity extends Activity {
private static final int TAKE_PHOTO = 1;
private static final int CROP_PHOTO = 2;
private Button btnPhoto;
private ImageView imgPhoto;
private Uri imgUri;
private Button btnAlbum;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_photo);
btnPhoto = (Button) findViewById(R.id.btn_photo);
imgPhoto = (ImageView) findViewById(R.id.img_photo);
btnAlbum = (Button) findViewById(R.id.btn_album);
btnAlbum.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//创建一个File对象,用于存储摄像头拍下的图片,这里命名为outputImg.jpg,并将它存放在手机SD卡的根目录下
//Environment.getExternalStorageDirectory()这个方法就是获取到手机SD卡的根目录
File outputImage = new File(Environment.getExternalStorageDirectory(), "output_image.jpg");
try {
if (outputImage.exists()) {
outputImage.delete();
}
outputImage.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
//调用Uri.fromFile 将File对象转化成Uri对象,这个Uri对象标识着outputImg.jpg这张图片的唯一地址
imgUri = Uri.fromFile(outputImage);
//构建Intent对象,Intent的action指定为android.media.action.GET_CONTENT允许用户选择特殊的数据并返回
Intent intent = new Intent("android.intent.action.GET_CONTENT");
//查看类型为image的数据
intent.setType("image/*");
//设置该图片可裁剪
intent.putExtra("crop", true);
//设置该图片可缩放
intent.putExtra("scale", true);
//调用Intent的putExtra指定图片的输出地址,这边为刚刚得到的Uri(即imgUri)对象
intent.putExtra(MediaStore.EXTRA_OUTPUT, imgUri);
startActivityForResult(intent, CROP_PHOTO);
}
});
btnPhoto.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//创建一个File对象,用于存储摄像头拍下的图片,这里命名为outputImg.jpg,并将它存放在手机SD卡的根目录下
//Environment.getExternalStorageDirectory()这个方法就是获取到手机SD卡的根目录
File outputImg = new File(Environment.getExternalStorageDirectory(), "tempImg.jpg");
try {
if (outputImg.exists()) {
outputImg.delete();
}
outputImg.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
//调用Uri.fromFile 将File对象转化成Uri对象,这个Uri对象标识着outputImg.jpg这张图片的唯一地址
imgUri = Uri.fromFile(outputImg);
//构建Intent对象,Intent的action指定为android.media.action.IMAGE_CAPTURE表示使用系统的拍照功能
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
//调用Intent的putExtra指定图片的输出地址,这边为刚刚得到的Uri(即imgUri)对象
intent.putExtra(MediaStore.EXTRA_OUTPUT, imgUri);
startActivityForResult(intent, TAKE_PHOTO); //启动活动
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case TAKE_PHOTO:
if (resultCode == RESULT_OK) {
//构建Intent对象,Intent的action指定为com.android.camera.action.CROP 表示使用系裁剪图片
Intent intent = new Intent("com.android.camera.action.CROP");
//查看类型为image的数据
intent.setDataAndType(imgUri, "image/*");
//设置该图片可缩放
intent.putExtra("scale", true);
//调用Intent的putExtra指定图片的输出地址,这边为刚刚得到的Uri(即imgUri)对象
intent.putExtra(MediaStore.EXTRA_OUTPUT, imgUri);
startActivityForResult(intent, CROP_PHOTO);//启动裁剪程序
}
break;
case CROP_PHOTO:
if (resultCode == RESULT_OK) {
try {
Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imgUri));
imgPhoto.setImageBitmap(bitmap);//将裁剪后的图片显示出来
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
break;
}
}
}
AndroidManifest.xml文件中声明权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
二、播放多媒体文件
在安卓中播放音频文件一般用 MediaPlayer
类来实现,播放视频文件主要用 VideoView
类来实现。
(一)MediaPlayer 常用方法:
MediaPlayer | 构造方法 |
---|---|
create | 创建一个要播放的多媒体 |
getCurrentPosition | 得到当前播放位置 |
getDuration | 得到文件的时间 |
getVideoHeight | 得到视频的高度 |
getVideoWidth | 得到视频的宽度 |
isLooping | 是否循环播放 |
isPlaying | 是否正在播放 |
pause | 暂停 |
prepare | 准备(同步) |
prepareAsync | 准备(异步) |
release | 释放MediaPlayer对象相关的资源 |
reset | 重置MediaPlayer对象为刚刚创建的状态 |
seekTo | 指定播放的位置(以毫秒为单位的时间) |
setAudioStreamType | 设置流媒体的类型 |
setDataSource | 设置多媒体数据来源(位置) |
setDisplay | 设置用SurfaceHolder来显示多媒体 |
setLooping | 设置是否循环播放 |
setOnButteringUpdateListener | 网络流媒体的缓冲监听 |
setOnErrorListener | 设置错误信息监听 |
setOnVideoSizeChangedListener | 视频尺寸监听 |
setScreenOnWhilePlaying | 设置是否使用SurfaceHolder来保持屏幕显示 |
setVolume | 设置音量 |
start | 开始播放 |
stop | 停止播放 |
(二) VideoView
和MediaPlaer
也比较类似,主要有以下常用方法:
MediaPlayer | 构造方法 |
---|---|
setVideoPath() | 设置要播放的视频文件的位置。 |
start() | 开始或继续播放视频。 |
pause() | 暂停播放视频。 |
resume() | 将视频重头开始播放。 |
seekTo() | 从指定的位置开始播放视频。 |
isPlaying() | 判断当前是否正在播放视频。 |
getDuration() | 获取载入的视频文件的时长。 |
1. 播放音频
activity_main.xml文件代码
package com.dak.administrator.firstcode.multi_media;
import android.Manifest;
import android.content.pm.PackageManager;
import android.media.MediaPlayer;
import android.os.Environment;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.dak.administrator.firstcode.R;
import java.io.File;
import java.io.IOException;
public class MediaActivity extends AppCompatActivity implements View.OnClickListener {
private MediaPlayer mediaPlayer = new MediaPlayer();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_media);
Button play = findViewById(R.id.play);
Button pause = findViewById(R.id.pause);
Button stop = findViewById(R.id.stop);
play.setOnClickListener(this);
pause.setOnClickListener(this);
stop.setOnClickListener(this);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
}else {
initMediaPlayer();
}
}
private void initMediaPlayer() {
try {
File file = new File(Environment.getExternalStorageDirectory(), "music.mp3");//music.mp3不存在
mediaPlayer.setDataSource(file.getPath());
mediaPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
initMediaPlayer();
}else {
Toast.makeText(this, "请获取存储权限", Toast.LENGTH_SHORT).show();
finish();
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.play:
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
}
break;
case R.id.pause:
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
break;
case R.id.stop:
if (!mediaPlayer.isPlaying()) {
mediaPlayer.reset();
initMediaPlayer();
}
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
}
}
}
activity_main.xml文件代码:
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.dak.administrator.firstcode.multi_media.MediaActivity">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/play"
android:text="play"
/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/pause"
android:text="pause"
/>
<Button
android:id="@+id/stop"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="stop" />
</LinearLayout>
2.播放视频
MainActivity.java文件代码
package com.dak.administrator.firstcode.multi_media;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Environment;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import android.widget.VideoView;
import com.dak.administrator.firstcode.R;
import java.io.File;
public class VideoActivity extends AppCompatActivity implements View.OnClickListener {
private VideoView videoView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video);
Button play = findViewById(R.id.play);
Button pause = findViewById(R.id.pause);
Button replay = findViewById(R.id.replay);
videoView = findViewById(R.id.video_view);
play.setOnClickListener(this);
pause.setOnClickListener(this);
replay.setOnClickListener(this);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
}else {
initVideoPath();
}
}
private void initVideoPath() {
File file = new File(Environment.getExternalStorageDirectory(), "movie.mp4");
videoView.setVideoPath(file.getPath());
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
initVideoPath();
}else {
Toast.makeText(this, "请获取存储权限", Toast.LENGTH_SHORT).show();
finish();
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.play:
if (!videoView.isPlaying()) {
videoView.start();
}
break;
case R.id.pause:
if (videoView.isPlaying()) {
videoView.pause();
}
break;
case R.id.replay:
if (videoView.isPlaying()) {
videoView.resume();//重新播放
}
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (videoView != null) {
videoView.suspend();//释放资源
}
}
}
activity_main.xml文件代码:
<?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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/play"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="play" />
<Button
android:id="@+id/pause"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="pause" />
<Button
android:id="@+id/replay"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="replay" />
</LinearLayout>
<VideoView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/video_view"
/>
</LinearLayout>
三、程序运行
1.在模拟器上运行
(1)选择下载好的模拟器,点击运行
(2)模拟器页面布局
(3)模拟器运行结果,点击按下Take Photo
按钮,打开模拟器相机
(4)点击按下Choose from Album
按钮,打开模拟器相册
2.在真实机上运行
(1)我本人用的手机型号是小米手机,到设置打开手机的开发者选项,由于各个手机厂商的打开方式都不同,下面列出一些常用手机:(如有错误的或是打不开的百度搜索一下)
小米手机:连续点击三下"MIUI 版本"
华为手机:连续点击"版本号"多次,直到屏幕提示已进入开发者模式。
三星手机:连续快速点击多次“软件信息”按钮,直到屏幕提示已进入开发者模式。
OPPO手机:连续点击"版本号"多次
VIVO手机:连续点击"软件版本号"多次
魅族手机:连续点击"版本号"多次
锤子手机:连续点击"软件版本"多次
努比亚手机:连续点击"版本号"多次
(2)进入开发者选项,打开USB调试,部分手机还需要打开USB安装。而我的就一定要打开才能安装,刚开始还没打开时USB安装时,怎么都安装不上,在Android Studio软件还报了一堆错误,通过自己查找资料、翻译,最终自己遇到的这问题解决了。
(3)手机运行结果
项目五
第十章
添加链接描述
D0-7E-35-BF-5D-79(2014)
目录
1.线程的基本用法
2.在子线程中更新UI
3.解析异步消息处理机制
4.使用AsyncTask**
一.线程的基本用法
二.在子线程中更新UI
这个时候我们就需要借助Java了
我们在java里面的activity里修改代码
代码如下
下就可以看到运行程序,程序崩溃了
然后修改代码
就可以看到成功了
三.解析异步消息处理机制
四.使用AsyncTask
到这里我们就结束了,上面就是我们的过程,希望能有帮助
添加链接描述
服务的基本用法
D0-7E-35-BF-5D-79(2014)
1.定义一个服务
2.启动和停止服务
3.活动和服务进行通信
一.定义一个服务
我们先建立一个Myservice项目
然后修改Myservice代码
二.启动和停止服务
定义好服务以后,我们就可以启动和停止这个服务了
首先修改activity的代码
到这里就实现了
三.活动和服务进行通信
首先修改Myservice
现在是main activity代码
现在就可以运行一下程序了
运行成功
希望对大家有点帮助
项目六
第一行代码 第十一章基于位置的服务
98-8D-46-9C-DC-2C(2022)
添加链接描述
转载连接:https://blog.csdn.net/m0_53046928/article/details/111122878
一、基于位置的服务简介
基于位置的服务简称LBS,随着移动互联网的兴起,这个技术在最近的几年里十分火爆。其实它本身并不是什么时髦的技术,主要的工作原理就是利用无线电通讯网络或GPS等定位方式来确定出移动设备所在的位置,而这种定位技术早在很多年前就已经出现了。
基于位置的服务,主要的工作原理是利用无线电通讯网络或 GPS 等定位方式来确定出移动设备所在的位置。LBS 所围绕的核心就是要确定出用户所在的位置。
通常有两种技术:
GPS 定位:
基于手机内置的 GPS 硬件直接和卫星交互来获取当前的经纬度信息,精确度高,但只能室外使用,室内基本无法接收到卫星的信号。
网络定位:
根据手机当前网络附近的三个基站进行测速,以此计算出手机和每个基站之间的距离,再通过三角定位确定一个大概位置,精确度一般,但室内外均可使用。
二、申请API Key
1、要在应用程序中使用百度LBS功能,需申请一个API Key(需有百度账号)。登录百度账号,打开http://developer.baidu.com/user/reg网址,填写注册信息
2、点击提交,进入验证邮箱界面
3、接着点击“去我的邮箱”,将会进入到我们刚才填写的邮箱当中,这时收件箱中应该会有一封刚刚收到的邮件,这就是百度发送给我们的验证邮件,点击邮件当中的链接就可以完成注册了。
4、接着访问http://lbsyun.baidu.com/apiconsole/key,同意百度开发者协议:
5、点击创建应用
那么,这个发布版SHA1和开发版SHA1又是个什么东西呢?这是我们申请APIKey所必须填写的一个字段,它指的是打包程序时所用签名文件的SHA1指纹。
一、通过Android Studio获取
- 打开Android Studio,进入Terminal工具,如下图所示:
- 输入命令行和密码,即可获取SHA1等信息;
命令行:keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey (注意目录选择、开发版本、发布版本等问题)
密码:原始密码一般为android,开发者根据实际情况填写。
二、使用 keytool(jdk自带工具)获取
-
运行进入控制台Windows:运行 -> 输入cmd -> 确定。
-
在控制台内,定位到.android文件夹,输入cd .android
-
输入命令行和密码,获取SHA1等信息
命令行:keytool -list -v -keystore debug.keystore;
密码:原始密码一般为android,开发者根据实际情况填写。
注意:
调试版本使用 debug.keystore,命令为:keytool -list -v -keystore debug.keystore。 发布版本使用 apk 对应的 keystore,命令为:keytool -list -v -keystore apk 的 keystore。
注意:一些电脑需要手动输入密钥,一些可以直接点击回车键。
适用于使用Android Studio开发工具的开发者。
三、包名的获取
Android Studio可以通过applicationId配置包名,如果配置了build.gradle文件,包名应该以applicaionId为准,防止build.gradle中的applicationId与 AndroidMainfest.xml中的包名不同,导致AK鉴权失败。
此时已完成了相应的注册填写步骤
三、使用百度定位
现在正是趁热打铁的好时机,新建一个LBSTest项目,包名应该就会自动被命名为com.example My11。
1.准备LBS SDK
先将百度 LBS 开放平台的 SDK 准备好,下载地址:http://lbsyun.baidu.com/sdk/download
如果链接打不开,也可以到上一步创建应用哪里,点击开发文档—Android 地图 SDK–产品下载
点击去下载,就会出现如图所示:
本章会用到基础地图和基础定位这两个 SDK,下载完后对该压缩包解压,libs 目录里就有我们所需要的一切了:
压缩包libs目录下的内容
下面把 libs 目录里的内容拷贝到我们的项目中:
(1)把 BaiduLBS_Android.jar 拷贝到项目 app 模块中的 libs 目录:
将 jar 包放置到 libs 目录中
(2)展开 src/main 目录,右击该目录→New→Directory,创建一个名为 jniLibs 的目录,用来存放 so 包,然后把压缩包里的其他所以目录直接复制到这里:
将 so 文件放置到 jniLibs 目录中
另外,记得点击顶部工具栏中的 Sync 按钮(下图中最左边的按钮)将 BaiduLBS_Android.jar 添加到当前项目的引用中。(如果无法引用的话可以到build.gradle里看看是否有这一段话
)没有的话右键点击放入的’jar’包选择add as library
2、确定自己位置的经纬度
(1)首先修改activity_main.xml中的代码,如下所示:
<LinearLayout xmlns :android="http:/ /schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent""android:layout_height="match_parent" >
<TextView
android :id="@+id/position_text_views"-android : layout_width="wrap_content"
android : layout_height="wrap_content" f>
</LinearLayout
(2)然后修改AndroidManifest.xml文件中的代码,如下所示:
添加所需权限
<!-- 百度 LBS 相关权限 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
(3)再注册一个百度 LBS SDK 中的服务
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.My11">
<meta-data
**android:name="com.baidu.lbsapi.API_KEY"
android:value="xoEORL5N4VMNHDr7rzQV6bqWAknpT2Zd" />**
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
**<service android:name="com.baidu.location.f"
android:enabled="true"
android:process=":remote">
</service>**
</application>
</manifest>
其中每个权限都是百度LBS SDK内部要用的,标签name部分是固定的value部分则是申请到的API Key.最后注册了LBS SDK中的服务
例如:android:value=“xoEORL5N4VMNHDr7rzQV6bqWAknpT2Zd”
(4)修改MainActivity:
public class MainActivity extends AppCompatActivity {
public LocationClient mLocationClient;
private TextView positionText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mLocationClient = new LocationClient(getApplicationContext());
mLocationClient.registerLocationListener(new MyLocationListener());
setContentView(R.layout.activity_main);
positionText = (TextView) findViewById(R.id.positions_text_view);
List<String> permissionList = new ArrayList<>();
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.
permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_DENIED) {
permissionList.add(Manifest.permission.ACCESS_FINE_LOCATION);
}
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.
permission.READ_PHONE_STATE) != PackageManager.PERMISSION_DENIED) {
permissionList.add(Manifest.permission.READ_PHONE_STATE);
}
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.
permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
permissionList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
if (!permissionList.isEmpty()) {
String[] permission = permissionList.toArray(new String[0]);
ActivityCompat.requestPermissions(MainActivity.this, permission, 1);
} else {
requestLocation();
}
}
private void requestLocation() {
mLocationClient.start();
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
switch (requestCode) {
case 1:
if (grantResults.length > 0) {
for (int result : grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "必须同意所有权限才能使用本程序",
Toast.LENGTH_SHORT).show();
finish();
return;
}
}
requestLocation();
} else {
Toast.makeText(this, "发生未知错误", Toast.LENGTH_SHORT).show();
finish();
}
break;
default:
}
}
public class MyLocationListener implements BDLocationListener {
@Override
public void onReceiveLocation(BDLocation Location) {
StringBuilder currentPosition = new StringBuilder();
currentPosition.append("纬度:").append(Location.getLatitude()).append("\n");
currentPosition.append("经线:").append(Location.getLongitude()).append("\n");
currentPosition.append("定位方式:");
if (Location.getLocType() == BDLocation.TypeGpsLocation) {
currentPosition.append("GPS");
} else if (Location.getLocType() == BDLocation.TypeNetWorkLocation) {
currentPosition.append("网络");
}
positionText.setText(currentPosition);
}
}
}
(5)运行程序,允许权限,移动手机查看变化
3、选择定位模式
GPS功能必须要由用户主动去开启才行,不然任何应用程序都无法使用GPS获取到手机当前的位置信息。
共有3种模式:
(1)Hight_Accuracy 高精度模式(默认模式),会在GPS信号正常的情况下优先使用GPS定位,在无法接收GPS信号时用网络定位。
(2)Battery_Saving 节电模式,只会使用网络定位。
(3)Device_Sensors 传感器模式,只会使用GPS定位。
强制使用Gps进行定位。
option.setLocationMode(LocationClientOption.LocationMode.Device_Sensors);
4、看得懂的位置信息
百度LBS SDK提供了很好的支持,只需调用一些简单接口聚能得到当前位置各种丰富信息。修改MainActivity:
option.setIsNeedAddress(true);
currenPosition.append("国家:").append(location.getCountry()).
append("\n");
currenPosition.append("省:").append(location.getProvince()).
append("\n");
currenPosition.append("市:").append(location.getCity()).
append("\n");
currenPosition.append("区:").append(location.getDistrict()).
append("\n");
currenPosition.append("街道:").append(location.getStreet()).
append("\n");
5、使用百度地图
需要用到百度提供的自定义控件 MapView
<com.baidu.mapapi.map.MapView
android:id="@+id/bmapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:focusable="true" />
MainActivity处:
private MapView mapView;
SDKInitializer.initialize(getApplicationContext());
mapView = (MapView) findViewById(R.id.bmapView);
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onDestroy() {
super.onDestroy();
mLocationClient.stop();
mapView.onDestroy();
baiduMap.setMyLocationEnabled(false);
}
6、移动到自己的位置
百度 LBS SDK 的 API 中提供了一个** BaiduMap** 类,是地图的总控制器,有了它就能对地图进行各种各样的操作了。获取其实例如下:
BaiduMap baiduMap = mapView.getMap();
百度地图将缩放级别的取值范围限定在3到19之间,也可取小数点位,值越大地图显示信息越精细,如把缩放级别设置成12.5,可以这样写:
MapStatusUpdate update = MapStatusUpdateFactory.zoomTo(12.5f);
baiduMap.animateMapStatus(update);
若要让地图移动到某个经纬度上,可以借助 LatLng 类,如将地图移动到北纬39.915°、东经116.404°,可以这样写:
LatLng ll = new LatLng(39.915,116.404);
MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(ll);
baiduMap.animateMapStatus(update);
接下来实现下 “移动到我的位置” 这个功能,修改活动中代码如下:
在这里插入图片描述
四、总结
郭霖总结:不得不说,本章中学到的知识应该还算是蛮有趣的吧?在这次的Android特色开发环节中我们主要学习了基于位置服务的工作原理和用法,借助百度提供的LBS SDK,我们可以随时确定自己当前位置的经纬度,并且还能获取到具体的省、市、区、街道等地址。之后又学习了百度地图的用法,不仅成功地将地图信息显示了出来,还综合利用了前面所学到的定位技术实现了一个较为完整的例子。
除了基于位置的服务之外,本章Git时间中继续对Git的用法进行了更深一一步的探究, 使得我们对分支和远程版本库的使用都有了一一定层次的了解。
我的总结:
这章本人并没有写任何的代码,(代码来源:第一行代码android)而是进行了通读.
项目七
第一行代码 第十二章(最佳UI体验) F8-94-C2-44-C2-AD(2025)
添加链接描述
文章目录
最佳UI体验
其实长久以来,大多数人都认为Android系统的UI并不算美观,至少没有 iOS系统的美观。以至于很多IT公司在进行应用界面设计的时候,为了保证双平台的统一性,强制要求Android端的界面风格必须和 iOS端一致。同一个操作系统中各个应用之间的界面统一性要远比一个应用在双平台的界面统一性重要得多,只有这样,才能给使用者带来更好的用户体验。
但问题在于,Android标准的界面设计风格并不是特别被大众所接受,很多公司都觉得自己完全可以设计出更加好看的界面,从而导致Android平台的界面风格长期难以得到统一。在2014年Google IO大会上重磅推出了一套全新的界面设计语言-—-—Material Design。
本章我们就将对Material Design进行一次深入的学习。
一、什么是 Material Design
Material Design是由谷歌的设计工程师基于优秀的设计原则,结合丰富的创意和科学技术所发明的一套全新的界面设计语言,包含了视觉、运动、互动效果等特性。
二、布局设计
1.布局代码分别如下
代码如下:
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:id="@+id/toolbar"
android:background="?attr/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:layout_scrollFlags="scroll|enterAlways|snap"
/>
<!-- layout_scrollFlags :scroll表示向上滚动时Toolbar滚动并实现隐藏,enenterAlways表示向下滚动时Toolabr向下滚动并重现
snap表示当Toolbar还没有完全隐藏或显示时,根据当前滚动的距离,选择隐藏还是显示 -->
</com.google.android.material.appbar.AppBarLayout>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/srf"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/recyclerview"
/>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<!-- 指定布局行为 -->
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/fab"
android:src="@drawable/pear"
android:layout_gravity="bottom|right"
android:layout_margin="16dp"
app:elevation="8dp"
/>
<!-- elevation给FloatingActionButton指定一个高度值,高度值越大,投影范围越大,投影效果越淡 -->
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<com.google.android.material.navigation.NavigationView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/nav_view"
android:layout_gravity="start"
app:menu="@menu/circleimagemenu"
app:headerLayout="@layout/headerlayout"/>
</androidx.drawerlayout.widget.DrawerLayout>
activity_main2.xml代码如下:
<androidx.coordinatorlayout.widget.CoordinatorLayout
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"
>
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="250dp"
android:id="@+id/appbar">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:contentScrim="@color/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<!--exitUntilCollapsed随着滚动完成折叠之后就保留在界面上,不在移出屏幕 -->
<ImageView
android:id="@+id/image2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax"/>
<androidx.appcompat.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:id="@+id/toolbar2"
app:layout_collapseMode="pin"/>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="15dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginTop="35dp"
app:cardCornerRadius="4dp">
<TextView
android:id="@+id/textview2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
/>
</androidx.cardview.widget.CardView>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:src="@drawable/pear"
app:layout_anchor="@id/toolbar2"
app:layout_anchorGravity="bottom|end"/>
<!--layout_anchor设置瞄点 -->
</androidx.coordinatorlayout.widget.CoordinatorLayout>
headerlayout.xml代码如下:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="180dp"> <!-- 180dp是NavigationView比较合适的高度 -->
<de.hdodenhof.circleimageview.CircleImageView
android:layout_width="70dp"
android:layout_height="70dp"
android:id="@+id/header_image"
android:src="@drawable/pear"
android:layout_centerInParent="true"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/header_textView1"
android:text="嘿嘿"
android:textSize="14sp"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:textColor="#191515"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/header_textView2"
android:text="哎呀"
android:textSize="14sp"
android:layout_above="@id/header_textView1"
android:textColor="#150A0A"
/>
</RelativeLayout>
item.xml代码
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_margin="5dp"
app:cardCornerRadius="4dp"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="100dp"
android:id="@+id/item_image"
android:scaleType="centerCrop"/> <!-- 指定图片的缩放模式,他可以让图片保持原有比例填充ImageView,并裁掉超出部分 -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/item_textview"
android:layout_gravity="center_horizontal"
android:layout_margin="5dp"
android:textSize="16sp"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
三、程序设计
1.分别创建3个文件夹如(Fruit)、(MainActivity2)、 (Mydapt)
MainActivity代码
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.navigation.NavigationView;
import com.google.android.material.snackbar.Snackbar;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class MainActivity extends AppCompatActivity {
DrawerLayout drawerLayout;
private SwipeRefreshLayout swipeRefreshLayout;
private Mydapt adapt;
private List<Fruit> list = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
NavigationView navigationView = (NavigationView)findViewById(R.id.nav_view);
Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
drawerLayout = (DrawerLayout)findViewById(R.id.drawerLayout);
ActionBar actionBar = getSupportActionBar();
if(actionBar != null){
actionBar.setDisplayHomeAsUpEnabled(true); //让导航按钮显示出来
actionBar.setHomeAsUpIndicator(R.mipmap.ic_launcher); //设置导航按钮图标,默认是返回的图标
}
navigationView.setCheckedItem(R.id.item_cgl1); //设置菜单项的默认选中
//对菜单项设置监听
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
drawerLayout.closeDrawers(); //将滑动菜单关闭
return true;
}
});
//FloatingActionButton点击事件
FloatingActionButton floatingActionButton = (FloatingActionButton)findViewById(R.id.fab);
floatingActionButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Snackbar.make(v,"Data delete",Snackbar.LENGTH_SHORT)
.setAction("Undo", new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,"click",Toast.LENGTH_SHORT).show();
}
})
.show();
}
});
//RecyclerView
addlist();
RecyclerView recyclerView = (RecyclerView)findViewById(R.id.recyclerview);
GridLayoutManager manager = new GridLayoutManager(MainActivity.this,2);
adapt = new Mydapt(list);
recyclerView.setLayoutManager(manager);
recyclerView.setAdapter(adapt);
//下拉刷新:
swipeRefreshLayout = (SwipeRefreshLayout)findViewById(R.id.srf);
swipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary); //设置颜色
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
refreshFruits();
}
});
}
private void refreshFruits() {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
@Override
public void run() {
addlist();
adapt.notifyDataSetChanged();
swipeRefreshLayout.setRefreshing(false); //刷新事件结束,并隐藏刷新进度条
}
});
}
}).start();
}
private void addlist() {
list.clear();
Fruit[] fruits = {new Fruit("grape",R.drawable.grape),new Fruit("orange",R.drawable.orange),
new Fruit("pear",R.drawable.pear),new Fruit("watemelon",R.drawable.watemelon)};
for(int i =0; i < 50 ;i++){
Random random = new Random();
int index = random.nextInt(fruits.length);
list.add(fruits[index]);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.toolbarmenu,menu);
return true;
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()){
case R.id.item1:
break;
case R.id.item2:
break;
case R.id.item3:
break;
case android.R.id.home:
drawerLayout.openDrawer(GravityCompat.START);
}
return true;
}
}
Fruit代码代码如下:
public class Fruit {
private String Name;
private int imageId;
public Fruit(String name, int imageId) {
Name = name;
this.imageId = imageId;
}
public String getName() {
return Name;
}
public int getImageId() {
return imageId;
}
}
MainActivity2代码
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import android.content.Intent;
import android.os.Bundle;
import android.view.MenuItem;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.google.android.material.appbar.CollapsingToolbarLayout;
public class MainActivity2 extends AppCompatActivity {
public static final String FRUIT_NAME = "fruit_name";
public static final String FRUIT_IMAGE_ID = "fruit_image_id";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Intent intent = getIntent();
String fruitName = intent.getStringExtra(FRUIT_NAME);
int imageId = intent.getIntExtra(FRUIT_IMAGE_ID,0);
Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar2);
CollapsingToolbarLayout collapsingToolbarLayout = (CollapsingToolbarLayout)findViewById(R.id.collapsing_toolbar);
ImageView imageView = (ImageView)findViewById(R.id.image2);
TextView textView = (TextView)findViewById(R.id.textview2);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if(actionBar != null){
actionBar.setDisplayHomeAsUpEnabled(true);
}
collapsingToolbarLayout.setTitle(fruitName);
Glide.with(this).load(imageId).into(imageView);
String fruitContent = geterateFruitContent(fruitName);
textView.setText(fruitContent);
}
private String geterateFruitContent(String fruitName) {
StringBuilder fruitContent = new StringBuilder();
for(int i = 0; i < 500; i++){
fruitContent.append(fruitName);
}
fruitContent.reverse();
return fruitContent.toString();
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()){
case android.R.id.home:
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
}
Mydapt代码
import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.cardview.widget.CardView;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import org.w3c.dom.Text;
import java.util.List;
public class Mydapt extends RecyclerView.Adapter<Mydapt.ViewHolder> {
private List<Fruit> list;
private Context mcontext;
public Mydapt(List<Fruit> list) {
this.list = list;
}
class ViewHolder extends RecyclerView.ViewHolder{
CardView cardView;
ImageView imageView;
TextView textView;
public ViewHolder(@NonNull View itemView) {
super(itemView);
cardView = (CardView) itemView;
imageView = itemView.findViewById(R.id.item_image);
textView = itemView.findViewById(R.id.item_textview);
}
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if(mcontext==null)
mcontext = parent.getContext();
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item,parent,false);
final ViewHolder viewHolder = new ViewHolder(view);
viewHolder.cardView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = viewHolder.getAdapterPosition();
Fruit fruit = list.get(position);
Intent intent = new Intent(mcontext,MainActivity2.class);
intent.putExtra(MainActivity2.FRUIT_NAME,fruit.getName());
intent.putExtra(MainActivity2.FRUIT_IMAGE_ID,fruit.getImageId());
mcontext.startActivity(intent);
}
});
return viewHolder;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Fruit fruit = list.get(position);
holder.textView.setText(fruit.getName());
Glide.with(mcontext).load(fruit.getImageId()).into(holder.imageView); //用Glide加载图片
}
@Override
public int getItemCount() {
return list.size();
}
}
(一)修改标题栏显示文字的内容
1、修改AndroidManifest中< activity>的label属性
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.revise_12_1">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity2"></activity>
<activity
android:name=".MainActivity"
android:label="this ok">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
(二)下拉刷新
在 Meterial Design 中,SwipeRefreshLayout 是用于实现下拉刷新的核心类,它由 support-v4 库提供,把要实现下拉刷新功能的控件放置到 SwipeRefreshLayout 中,就能让这个控件支持下拉刷新。
在内容外嵌套:
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<!--appbar_scrolling_view_behavior 唯一的作用是把自己(使用者)放到AppBarLayout的下面-->
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v4.widget.SwipeRefreshLayout>
上述代码值得注意的是,由于 RecyclerView 变成了 SwipeRefreshLayout 的子控件,因此之前用 app:layout_behavior 声明布局行为要移到 SwipeRefreshLayout 中才行。
修改活动:
// 下拉刷新
swipeRefresh = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh);
swipeRefresh.setColorSchemeResources(R.color.colorPrimary);//设置刷新进度条颜色
swipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
// 处理刷新逻辑
refreshPartner();
}
});
处理刷新逻辑(模拟)
/**
* 下拉刷新数据(为简单起见没和网络交互)
*/
private void refreshPartner() {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
@Override
public void run() {
initPartner();//重新生成数据
adapter.notifyDataSetChanged();//通知数据变化
swipeRefresh.setRefreshing(false);//隐藏刷新进度条
}
});
}
}).start();
}
四.程序运行
1.虚拟机上运行结果
2.真实机上运行结果
总结
学完了本章的所有知识,你有没有觉得无比兴奋呢?反正我是这么觉得的。本章我们的收获实在是太多了,从一个什么都没有的空项目,经过一章的学习,最后实现了一个功能如此丰富、界面如此华丽的应用,还有什么事情比这个更让我们有成就感吗?
本章中我们充分利用了Design Support库、support-v4库、appcompat-v7库,以及一些开源项目来实现一个了高度Material化的应用程序。