文章目录
- MyTool工具界面:便签
- ♦ 回顾
- ♦ 设置 activity_my_tool.xml 界面
- ♦ 编写 MyToolActivity 实现功能界面跳转
- ♦ 创建 activity_time_count.xml 便签界面
- ♦ 编写 NoteActivity 实现功能
- ♦ 优化 NoteActivity 实现打开即显示功能
- ♦ 优化 NoteActivity 实现文本框字数动态显示功能
- ♦ 展示
MyTool工具界面:便签
♦ 回顾
- 上一篇是对之前的秒表功能的扩展,在秒表的基础上进行了记录行为。
- 今天,我们将要制作一个全新的功能:便签
♦ 设置 activity_my_tool.xml 界面
- 添加一个新的
按钮组件
:便签
<Button
android:id="@+id/note"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="250dp"
android:text="便签"
android:textSize="16dp"/>
返回顶部
♦ 编写 MyToolActivity 实现功能界面跳转
public class MyToolActivity extends AppCompatActivity {
TextView welcome;
Button net, call, quick_call,flashlight,timecount,timerecoder,note;
//权限请求:载入界面、特定情况触发
//定义权限 --- 动态权限,申请哪一个就启动哪一个,通常为常量
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.CALL_PHONE
};
//请求状态码
private static int REQUEST_PERMISSION_CODE = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_tool);
.........................
// 获取工具组件
net = findViewById(R.id.net);
call = findViewById(R.id.call);
quick_call = findViewById(R.id.quick_call);
flashlight = findViewById(R.id.flashlight);
timecount = findViewById(R.id.timecount);
timerecoder = findViewById(R.id.timerecoder );
note = findViewById(R.id.note);
.........................
// 秒表界面跳转
note.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 创建页面跳转
Intent intent = new Intent();
intent.setClass(MyToolActivity.this,NoteActivity.class);
startActivity(intent);
}
});
}
}
返回顶部
♦ 创建 activity_time_count.xml 便签界面
- 基本布局、背景(这里我们换了一张背景图)
- 配置组件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.myapplication.NoteActivity"
android:background="@drawable/sky">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="51dp"
android:text="备 忘 录"
android:textSize="24sp"
android:textStyle="bold"/>
<Button
android:id="@+id/note_save" 保存按钮
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentBottom="true"
android:layout_marginStart="48dp"
android:layout_marginLeft="48dp"
android:layout_marginBottom="65dp"
android:alpha="0.7"
android:background="#80987654"
android:text="Save" />
<Button
android:id="@+id/note_clear" 清空按钮
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_marginEnd="51dp"
android:layout_marginRight="51dp"
android:layout_marginBottom="65dp"
android:alpha="0.7" 按钮透明度
android:background="#80987654"
android:text="Clear" />
<EditText
android:id="@+id/editText" 便签编辑文本框
android:layout_width="355dp"
android:layout_height="wrap_content"
android:layout_above="@id/note_clear"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginStart="27dp"
android:layout_marginLeft="27dp"
android:layout_marginTop="106dp"
android:layout_marginRight="20dp"
android:layout_marginBottom="80dp"
android:background="@null"
android:ems="10"
android:gravity="start|top"
android:hint="请输入文本~" 提示文本
android:inputType="textMultiLine"
android:minLines="18" 设置编辑文本的最大行数
android:textSize="22dp" />
<TextView
android:id="@+id/number" 左上显示方便签状态
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_marginTop="80dp"
android:layout_marginEnd="33dp"
android:layout_marginRight="33dp"
android:text="当前字数:0" />
</RelativeLayout>
返回顶部
♦ 编写 NoteActivity 实现功能
- 实现文本框内容的输出保存、清除功能
- 在这里其实本质上就是
I/O操作
,将获取到的文本框中的内容写入到一个文件中。
package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import com.example.myapplication_test.R;
import java.io.FileOutputStream;
public class NoteActivity extends AppCompatActivity {
Button clear,save; // 清除文本、保存文本按钮
TextView state; // 便签状态显示
static EditText inputText; // 便签文本输入
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_note);
clear = findViewById(R.id.note_clear);
save = findViewById(R.id.note_save);
state = findViewById(R.id.number);
inputText = findViewById(R.id.editText);
// 输入文本监听
inputText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
inputText.setCursorVisible(true);
}
});
// 清空按钮监听
clear.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 清除相当于空文本覆盖了原文本
input("","清除成功");
inputText.setText("");
}
});
// 保存按钮监听
save.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 将文本框输入的内容写入文件中
input(inputText.getText().toString(),"保存成功");
}
});
}
// 输出方法 --- 向文本文件中写数据
public void input(String text,String text1){
FileOutputStream out = null;
try {
out = openFileOutput("txt", Context.MODE_PRIVATE);
out.write(text.getBytes());
} catch (Exception e){
e.printStackTrace();
} finally {
// 最终保存成功或清除成功完善、关闭资源
try{
out.flush();
Toast.makeText(NoteActivity.this,text1,Toast.LENGTH_SHORT).show();
out.close();
} catch (Exception e){
e.printStackTrace();
}
}
}
}
-
Context.MODE_PRIVATE
:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容,如果想把新写入的内容追加到原文件中。可以使用Context.MODE_APPEND -
Context.MODE_APPEND
:模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。 -
Context.MODE_WORLD_READABLE
和Context.MODE_WORLD_WRITEABLE
:用来控制其他应用是否有权限读写该文件。
-
MODE_WORLD_READABLE
:表示当前文件可以被其他应用读取; -
MODE_WORLD_WRITEABLE
:表示当前文件可以被其他应用写入。
通过测试,会发现一个问题。就是在保存好便签之后,退出来再次进入时,显示的内容为空。下面做一个优化,就是当我们每次打开的时候,会显示出上一次保存的数据。
返回顶部
♦ 优化 NoteActivity 实现打开即显示功能
package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import com.example.myapplication_test.R;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class NoteActivity extends AppCompatActivity {
Button clear,save; // 清除文本、保存文本按钮
TextView state; // 便签状态显示
static EditText inputText; // 便签文本输入
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_note);
clear = findViewById(R.id.note_clear);
save = findViewById(R.id.note_save);
state = findViewById(R.id.number);
inputText = findViewById(R.id.editText);
// 调用方法,显示之前保存的便签文件
onload();
// 输入文本监听
inputText.setOnClickListener(new View.OnClickListener() {
..........
});
// 清空按钮监听
clear.setOnClickListener(new View.OnClickListener() {
..........
});
// 保存按钮监听
save.setOnClickListener(new View.OnClickListener() {
..........
});
}
// 输出方法 --- 向文本文件中写数据
public void input(String text,String text1){
..........
}
// 打开即显示
public void onload(){
FileInputStream in = null;
try {
in = openFileInput("txt");
if (in.available()==0){
return; // 说明没有数据要读取了
} else {
byte[] con = new byte[in.available()];
while(in.read(con)!=-1){
}
inputText.setText(new String(con)); // 获取要显示的数据
inputText.setSelection(inputText.getText().length()); // 设置光标
inputText.setCursorVisible(true);
}
} catch (Exception e){
e.printStackTrace();
}
}
}
关于InputStream类的available()
方法
- 要一次读取多个字节时,经常用到InputStream.available()方法,这个方法可以在读写操作前先得知数据流里有多少个字节可以读取。
- 需要注意的是,如果这个方法用在从本地文件读取数据时,一般不会遇到问题,但如果是用于网络操作,就经常会遇到一些麻烦。比如,Socket通讯时,对方明明发来了1000个字节,但是自己的程序调用available()方法却只得到900,或者100,甚至是0,感觉有点莫名其妙,怎么也找不到原因。 其实,这是因为网络通讯往往是间断性的,一串字节往往分几批进行发送。本地程序调用available()方法有时得到0,这可能是对方还没有响应,也可能是对方已经响应了,但是数据还没有送达本地。对方发送了1000个字节给你,也许分成3批到达,这你就要调用3次available()方法才能将数据总数全部得到。
返回顶部
♦ 优化 NoteActivity 实现文本框字数动态显示功能
- 通过
inputText.addTextChangedListener
的监听事件可以对文本框的变化进行监听处理。
// 增加文本框文本字数动态监听
inputText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// 文本框改变前的监听方法 --- 这里不需改动
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// 文本框改动的时候的监听方法
}
@Override
public void afterTextChanged(Editable s) {
// 文本框改动后的监听方法 --- 我们要计数,肯定是在写完内容后进行统计
// 参数Editable s 就是当前的文本编辑框,我们可以通过他获取文本的长度,同时加上额外的限制
state.setText("当前字数:"+s.toString().length()+"/220");
if (s.toString().length()>220){
state.setText("220/220");
// 当字数超过220之后,要将多余的文本删除 --- 不可编辑状态
int max = 220; // 指向最大字数处的光标
int end = inputText.getSelectionEnd(); // 获取真实结束时的光标位置
s.delete(max,end); // 删除超出最大文本字数限制的文本
inputText.setText(s); // 保留删除后的文本 --- 最大限制
inputText.setSelection(max); // 将指针指向最大字数处
inputText.setCursorVisible(true); // 显示光标
Toast.makeText(getApplicationContext(), "超出文本限制", Toast.LENGTH_SHORT).show(); //弹出提示框
}
}
});
♦ 展示
便签
根据以上的展示,继续做出最后的优化:在保存了退出,再次进入的时候,文本框字数状态栏会重置,这里只需要在onload()方法中加一行显示文本字数的代码即可。
// 打开即显示
public void onload(){
FileInputStream in = null;
try {
in = openFileInput("txt");
if (in.available()==0){
return; // 说明没有数据要读取了
} else {
byte[] con = new byte[in.available()];
while(in.read(con)!=-1){
}
inputText.setText(new String(con)); // 获取要显示的数据
state.setText("当前字数:"+inputText.getText().toString().length()+"/220"); // 显示文本字数
inputText.setSelection(inputText.getText().length()); // 设置光标
inputText.setCursorVisible(true);
}
} catch (Exception e){
e.printStackTrace();
}
}
返回顶部