当前位置:网站首页>手机便签应用
手机便签应用
2022-07-01 12:25:00 【Comeจุ๊】
便签应用
便签应用实现的功能
1、便签应用的增删改查
2、修改便签应用的皮肤,和主页上的便签颜色同步
3、对便签应用的时间显示做一个特定显示:当天显示–>今天 hh:mm ,昨天显示 --> 昨天 hh:mm,本周内显示–> 周几 hh:mm,否则显示 yyyy/MM/dd
4、在便签的编辑页面,可以设置便签的提醒时间,第一次选择日期,第二次选择时间
5、长按主页对便签进行整体操作
6、可以为便签设置顶置设置,可以单个设置,也可以批量设置
7、当便签全部顶置的时候,长按编辑的顶置
按钮变成了取消顶置
按钮
7、当选择未顶置的标签,会提示是否顶置标签,反之如此
便签应用的整体思路和代码
1、首先对便签应用的主页布局进行构思,
具体的数据显示使用RecyclerView
进行数据展示,主页的布局显示一个新建按钮,并且其中隐藏着长按之后的布局(取消、全选、顶置、删除);并在布局中的visibility
设为 gone
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:background="@color/background" android:orientation="vertical">
<Toolbar android:id="@+id/id_note_toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/toolbar" android:visibility="gone">
<Button android:id="@+id/header_cancel" android:layout_width="wrap_content" android:layout_height="40dp" android:layout_gravity="left" android:gravity="center" android:background="@drawable/button_style" android:backgroundTint="@color/toolbar_button" android:text="@string/press_cancel" android:textSize="15sp"/>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:textColor="@color/white" android:text="@string/press_edit" android:textSize="20sp"/>
<Button android:id="@+id/header_selectAll" android:layout_width="wrap_content" android:layout_height="40dp" android:layout_gravity="right" android:background="@drawable/button_style" android:backgroundTint="@color/toolbar_button" android:textColor="@color/white" android:layout_marginRight="20dp" android:text="@string/press_selectAll" android:textSize="15sp"/>
</Toolbar>
<androidx.recyclerview.widget.RecyclerView android:id="@+id/recycler" android:layout_marginTop="10dp" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1">
</androidx.recyclerview.widget.RecyclerView>
<LinearLayout android:id="@+id/id_note_add" android:layout_width="match_parent" android:layout_height="120dp" android:layout_weight="1" android:background="#302424" android:orientation="vertical" android:visibility="visible">
<ImageView android:id="@+id/add_pic" android:layout_width="20dp" android:layout_height="20dp" android:src="@mipmap/ic_note_add" android:layout_gravity="center" android:layout_weight="1"/>
<TextView android:id="@+id/add_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:textSize="15sp" android:text="@string/main_add" android:gravity="center" android:textColor="@color/white" android:layout_weight="1"/>
</LinearLayout>
<!-- 隐藏底部导航栏 ==> 顶置和删除按钮 -->
<LinearLayout android:id="@+id/id_note_bottom" android:layout_width="match_parent" android:layout_height="180dp" android:layout_weight="1" android:orientation="horizontal" android:visibility="gone" android:background="@color/purple_200">
<LinearLayout android:id="@+id/header_top" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center" android:background="@color/toolbar" android:orientation="vertical">
<ImageView android:layout_width="20dp" android:layout_height="20dp" android:layout_gravity="center" android:src="@mipmap/ic_note_edit_top"/>
<TextView android:id="@+id/tv_header_top" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:textColor="@color/white" android:textSize="15sp" android:paddingTop="5dp" android:text="@string/home_top"/>
</LinearLayout>
<TextView android:layout_width="1dp" android:layout_height="match_parent" android:background="#4f4545"/>
<LinearLayout android:id="@+id/header_delete" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" android:background="@color/toolbar" android:gravity="center" android:orientation="vertical">
<ImageView android:layout_width="20dp" android:layout_height="20dp" android:layout_gravity="center" android:src="@mipmap/ic_note_edit_delete"/>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:textColor="@color/white" android:textSize="15sp" android:paddingTop="5dp" android:text="@string/delete"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
初始主页布局:
隐藏的主页布局(长按之后显示):
2、对每个item的具体布局,使用RecyclerView布局显示
note_item.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="wrap_content" android:orientation="horizontal" android:padding="5dp">
<LinearLayout android:id="@+id/lr_list_container" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:background="@color/menu_theme4">
<ImageView android:id="@+id/iv_topTab" android:visibility="invisible" android:layout_width="20dp" android:layout_height="20dp" android:src="@mipmap/ic_header_top"/>
<LinearLayout android:id="@+id/recycler_background" android:layout_width="wrap_content" android:layout_height="100dp" android:layout_weight="1" android:orientation="horizontal" android:padding="10dp">
<TextView android:id="@+id/tv_content" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/tv_time" android:layout_gravity="center" android:layout_marginTop="5dp" android:maxLines="2" android:text="我也不想这样" android:textColor="@color/black" android:textSize="20sp" />
</LinearLayout>
<LinearLayout android:layout_width="wrap_content" android:layout_height="100dp" android:orientation="vertical">
<TextView android:id="@+id/tv_time" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:layout_marginRight="10dp" android:paddingLeft="5dp" android:text="2021/5/30 02:30" android:textColor="@color/black" android:textSize="16sp" android:layout_weight="1" android:gravity="right"/>
<LinearLayout android:layout_width="150dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="right" android:orientation="horizontal">
<ImageView android:id="@+id/iv_remind" android:layout_width="30dp" android:layout_height="30dp" android:layout_gravity="center_vertical" android:layout_marginRight="10dp" android:src="@mipmap/ic_note_clock" android:visibility="visible" />
<CheckBox android:id="@+id/checkbox" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:buttonTint="#ffffff" android:checked="false" android:gravity="center_vertical" android:scaleX="1.5" android:scaleY="1.5" android:visibility="gone" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
显示效果:checkbox进行隐藏(gone),当长按的时候,出现checkbox
3、recyclerView的适配器代码
RecyclerAdapter.java
package com.tinno.adapter;
import static android.view.View.VISIBLE;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.Toolbar;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.recyclerview.widget.RecyclerView;
import com.tinno.bean.Note;
import com.tinno.db.NoteDbHelper;
import com.tinno.sticky_note.EditNoteActivity;
import com.tinno.sticky_note.MainActivity;
import com.tinno.sticky_note.R;
import com.tinno.utils.FormatTime;
import java.io.Serializable;
import java.util.List;
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.RecyclerViewHolder> {
private static final String TAG = "RecyclerAdapter";
private List<Note> mBeanList;
private Context mContext;
private boolean showIcon = false;
private int flag = 0; //点击的数量
public boolean isCheck;
private LinearLayout mNoteAdd,mNoteBottom;
private Toolbar noteToolbar;
public RecyclerAdapter(Context context, List<Note> mBeanList) {
this.mContext = context;
this.mBeanList = mBeanList;
}
@NonNull
@Override
public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.note_item, parent, false);
return new RecyclerViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull RecyclerViewHolder holder, int position) {
Note note = mBeanList.get(position);
holder.mTvCreateTime.setText(FormatTime.FormatTimeForDb(note.getCreatedTime()));
holder.mTvContent.setText(note.getContent());
holder.lrContainer.setBackgroundColor(note.getColor());
// 为控件设置长按点击事件
holder.lrContainer.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
//对flag进行一个自增,当flag从开始点击的时候,当flag是2的除数的时候,showIcon设置false,反之设为true;
flag++;
Log.d(TAG, "showIcon " + showIcon);
// 设置一个全部变量,使长按点击的时候,状态变为true,并调用 notifyItemRangeChanged(int positionStart,int itemCount)方法进行从指定位置刷新,刷新多少个
//Toast.makeText(mContext, "showIcon的状态" + showIcon, Toast.LENGTH_SHORT).show();
if (flag % 2 == 0 ){
showIcon = false;
}else {
showIcon = true;
}
showOrHide(showIcon);
//Toast.makeText(mContext, "获取该item的id" + mBeanList.get(position), Toast.LENGTH_SHORT).show();
notifyItemRangeChanged(0,mBeanList.size());
return true;
}
});
// 判断showIcon的状态是否为true,为true的时候,checkbox显示,反正则隐藏
holder.mCheckBox.setVisibility(showIcon ? VISIBLE : View.GONE);
/** * When the user clicks the button, the content of the memo is passed to AddNoteActivity */
holder.lrContainer.setOnClickListener(view -> {
Intent intent = new Intent(mContext, EditNoteActivity.class);
intent.putExtra("note",note);
Log.d(TAG, "adapter向activity中传的值为: " + note.getId());
mContext.startActivity(intent);
});
// 判断是否设置了闹钟提醒时间,若没有设置提醒时间,闹钟图标进行隐藏
NoteDbHelper noteDbHelper = new NoteDbHelper(mContext);
List<Note> noteList = noteDbHelper.queryAllFromDb();
if (TextUtils.isEmpty(noteList.get(position).getRemind())){
//Log.d(TAG, "onBindViewHolder: " + 123);
holder.mTvRemind.setVisibility(View.GONE);
}else {
holder.mTvRemind.setVisibility(VISIBLE);
holder.mTvRemind.setOnClickListener(view -> {
showDialog(noteList.get(position).getRemind());
});
}
// 为顶置便签内容设置顶置标签
if (noteList.get(position).getIsTop() == 1){
holder.mIvTopTab.setVisibility(VISIBLE);
}else if (noteList.get(position).getIsTop() == 0){
holder.mIvTopTab.setVisibility(View.INVISIBLE);
}
}
// 点击闹钟图标,弹出一个dialog,用来显示提示的内容和提示的时间
public void showDialog(String str){
AlertDialog dialog = new AlertDialog.Builder(mContext)
.setTitle("事件提醒")
.setMessage(str + "\n" + str)
.create();
dialog.show();
}
// 获取MainActivity中的控件,并对该控件进行显示和隐藏
public void showOrHide(boolean isShow){
mNoteAdd = ((MainActivity) mContext).findViewById(R.id.id_note_add);
mNoteBottom = ((MainActivity) mContext).findViewById(R.id.id_note_bottom);
noteToolbar = ((MainActivity) mContext).findViewById(R.id.id_note_toolbar);
if (isShow){
mNoteAdd.setVisibility(View.GONE);
mNoteBottom.setVisibility(VISIBLE);
noteToolbar.setVisibility(VISIBLE);
}else {
mNoteAdd.setVisibility(VISIBLE);
mNoteBottom.setVisibility(View.GONE);
noteToolbar.setVisibility(View.GONE);
}
}
@Override
public int getItemCount() {
return mBeanList == null ? 0 : mBeanList.size();
}
@Override
public long getItemId(int position) {
return position;
}
public class RecyclerViewHolder extends RecyclerView.ViewHolder {
private TextView mTvCreateTime;
private TextView mTvContent;
private ImageView mTvRemind,mIvTopTab;
private ViewGroup lrContainer;
private LinearLayout recycler_background;
private CheckBox mCheckBox;
public RecyclerViewHolder(@NonNull View itemView) {
super(itemView);
mTvCreateTime = itemView.findViewById(R.id.tv_time);
mTvContent = itemView.findViewById(R.id.tv_content);
mTvRemind = itemView.findViewById(R.id.iv_remind);
lrContainer = itemView.findViewById(R.id.lr_list_container);
mCheckBox = itemView.findViewById(R.id.checkbox);
recycler_background = itemView.findViewById(R.id.recycler_background);
mIvTopTab = itemView.findViewById(R.id.iv_topTab);
// 多选框的点击事件
mCheckBox.setOnClickListener(view -> {
if (mCheckBox.isChecked()){
mOnItemClickListener.onRecyclerItemClick(getAdapterPosition());
}
});
}
}
private OnRecyclerItemClickListener mOnItemClickListener;
//设置监听的方法
public void setRecyclerItemClickListener(OnRecyclerItemClickListener listener){
mOnItemClickListener = listener;
}
//自定义设置一个监听器
public interface OnRecyclerItemClickListener{
void onRecyclerItemClick(int position);
}
}
4、主启动器的代码,
并为主页面的一些控件设置点击事件
MainActivity.java
package com.tinno.sticky_note;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.tinno.adapter.RecyclerAdapter;
import com.tinno.bean.Note;
import com.tinno.db.NoteDbHelper;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = "MainActivity";
private Context mContext;
private List<Note> data;
private RecyclerView mRecyclerView;
private RecyclerAdapter mRecyclerAdapter;
private List<String> list;
private NoteDbHelper mNoteDbHelper = new NoteDbHelper(this);
private LinearLayout mNoteAdd;
private Button headerCancel,headerSelectAll;
private LinearLayout headerTop,headerDelete;
private TextView tvHeaderTop;
private ImageView addpic; //添加图标
private Intent intent;
private Handler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this;
mNoteAdd = findViewById(R.id.id_note_add);
mNoteAdd.setOnClickListener(this);
initView();
}
@Override
protected void onResume() {
super.onResume();
mRecyclerView = (RecyclerView) findViewById(R.id.recycler);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(mContext);
mRecyclerView.setLayoutManager(linearLayoutManager);
mNoteDbHelper = new NoteDbHelper(mContext);
data = new ArrayList<>();
Log.d(TAG, "init: ....." );
data = mNoteDbHelper.queryAllFromDb();
// Log.d(TAG, "init: " + data);
mRecyclerAdapter = new RecyclerAdapter(mContext,data);
mRecyclerView.setAdapter(mRecyclerAdapter);
// 全部顶置内容改变顶置为取消顶置
ChangeTopButtonContent();
// 获取点击的recyclerview中的checkbox
show();
}
// 获取RecyclerView中checkBox的选择框内容
public void show(){
list = new ArrayList<>();
mRecyclerAdapter.setRecyclerItemClickListener(position -> {
list.add(data.get(position).getId());
Log.d(TAG, "show: " + list);
//Toast.makeText(mContext, "是否顶置" + data.get(position).getIsTop(), Toast.LENGTH_SHORT).show();
if (data.get(position).getIsTop() == 1){
Toast.makeText(mContext, "是否取消顶置", Toast.LENGTH_SHORT).show();
tvHeaderTop.setText("取消顶置");
}else {
Toast.makeText(mContext, "是否顶置", Toast.LENGTH_SHORT).show();
tvHeaderTop.setText("顶置");
}
});
}
// 若所有标签进行顶置,顶置按钮变为取消顶置,若不然,顶置按钮不变
public void ChangeTopButtonContent(){
List<Integer> list = new ArrayList<>();
for (Note datum : data) {
list.add(datum.getIsTop());
}
if (list != null){
int first = list.get(0);
for (Integer integer : list) {
if(integer.equals(first)){
tvHeaderTop.setText("取消顶置");
}else {
tvHeaderTop.setText("顶置");
}
}
}
}
public void initView(){
headerCancel = (Button) findViewById(R.id.header_cancel);
headerSelectAll = (Button) findViewById(R.id.header_selectAll);
headerTop = (LinearLayout) findViewById(R.id.header_top);
headerDelete = (LinearLayout) findViewById(R.id.header_delete);
tvHeaderTop = (TextView) findViewById(R.id.tv_header_top);
addpic = (ImageView) findViewById(R.id.add_pic);
headerCancel.setOnClickListener(this);
headerSelectAll.setOnClickListener(this);
headerTop.setOnClickListener(this);
headerDelete.setOnClickListener(this);
addpic.setOnClickListener(this);
}
// 返回至主页的完美状态
public void showHome(){
RecyclerAdapter adapter = new RecyclerAdapter(mContext,data);
adapter.showOrHide(false);
onResume();
}
// 设置便签顶置事件
public void setThingTop(){
// 对从数据库查询到所有的数组内容进行遍历
for (Note datum : data) {
Log.d(TAG, "onClick: " + datum);
// 对checkbox点击事件进行遍历,获取id
for (String noteId : list){
// 判断数据库的id和checkbox获取内容的id是否相等,相等则进行下一步操作
if (datum.getId().equals(noteId)){
Log.d(TAG, "onClick: -------------------------------------------");
Log.d(TAG, "获取的事件: " + datum.getContent() + "=>" + datum.getId());
Note n = new Note();
n.setId(datum.getId());
n.setContent(datum.getContent());
n.setRemind(datum.getRemind());
n.setColor(datum.getColor());
n.setCreatedTime(datum.getCreatedTime());
if (tvHeaderTop.getText().toString().equals("顶置")){
n.setIsTop(1);
}else if (tvHeaderTop.getText().toString().equals("取消顶置")){
n.setIsTop(0);
}
mNoteDbHelper.updateData(n);
Log.d(TAG, "获取新的Note对象:" + n);
Log.d(TAG, "onClick: ---------------------------------------------" );
}
}
}
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.add_pic:
intent = new Intent(this, AddNoteActivity.class);
startActivity(intent);
break;
case R.id.header_cancel:
showHome();
break;
case R.id.header_selectAll:
break;
case R.id.header_top:
setThingTop();
showHome();
break;
case R.id.header_delete:
for (String s : list) {
mNoteDbHelper.deleteFromDbById(s);
}
showHome();
break;
}
}
}
5、创建数据库
为了存储数据的方法,为便签应用创建noteSql
数据库,并创建 note
数据表,并在该类中初始化数据库操作的CURD的方法。
NoteDbHelper.java
package com.tinno.db;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
import com.tinno.bean.Note;
import java.util.ArrayList;
import java.util.List;
/** * Notes Database class */
public class NoteDbHelper extends SQLiteOpenHelper {
private static final String TAG = "NoteDbHelper";
private Context context;
private static final String DB_NAME = "noteSql.db";
private static final String NOTE_TABLE_NAME = "note";
// Database Version
private static final int DATABASE_VERSION =1;
private static final String CREATE_TABLE_SQL = "CREATE TABLE IF NOT EXISTS " + NOTE_TABLE_NAME + " (id INTEGER PRIMARY KEY AUTOINCREMENT, content TEXT, create_time TEXT, remind TEXT, color TEXT,isTop TEXT)";
public NoteDbHelper(Context context){
super(context,DB_NAME,null,DATABASE_VERSION);
this.context = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE_SQL);
Toast.makeText(context, "创建数据库成功", Toast.LENGTH_SHORT).show();
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
/** * Query all contents of the database * @return */
public List<Note> queryAllFromDb(){
SQLiteDatabase db = getWritableDatabase();
List<Note> noteList = new ArrayList<>();
Cursor cursor = db.query(NOTE_TABLE_NAME, null, null, null, null, null, "isTop DESC");
if (cursor != null){
while (cursor.moveToNext()){
String id = cursor.getString(cursor.getColumnIndexOrThrow("id"));
String content = cursor.getString(cursor.getColumnIndexOrThrow("content"));
String createTime = cursor.getString(cursor.getColumnIndexOrThrow("create_time"));
String remind = cursor.getString(cursor.getColumnIndexOrThrow("remind"));
int color = cursor.getInt(cursor.getColumnIndexOrThrow("color"));
int isTop = cursor.getInt(cursor.getColumnIndexOrThrow("isTop"));
Note note = new Note();
note.setId(id);
note.setContent(content);
note.setCreatedTime(createTime);
note.setRemind(remind);
note.setColor(color);
note.setIsTop(isTop);
noteList.add(note);
}
cursor.close();
}
return noteList;
}
public long insertData(Note note){
SQLiteDatabase db = getWritableDatabase();
ContentValues values = new ContentValues();
values.put("content",note.getContent());
values.put("create_time",note.getCreatedTime());
values.put("remind",note.getRemind());
values.put("color",note.getColor());
values.put("isTop",note.getIsTop());
return db.insert(NOTE_TABLE_NAME,null,values);
}
public int deleteFromDbById(String id) {
SQLiteDatabase db = getWritableDatabase();
return db.delete(NOTE_TABLE_NAME, "id like ?", new String[]{
id});
}
public int updateData(Note note) {
SQLiteDatabase db = getWritableDatabase();
ContentValues values = new ContentValues();
values.put("content", note.getContent());
values.put("create_time", note.getCreatedTime());
values.put("remind",note.getRemind());
values.put("color",note.getColor());
values.put("isTop",note.getIsTop());
Log.d(TAG, "updateData: " + values);
return db.update(NOTE_TABLE_NAME, values, "id like ?", new String[]{
note.getId()});
}
public List<Note> queryFromDbByContent(String content) {
if (TextUtils.isEmpty(content)) {
return queryAllFromDb();
}
SQLiteDatabase db = getWritableDatabase();
List<Note> noteList = new ArrayList<>();
Cursor cursor = db.query(NOTE_TABLE_NAME, null, "content like ?", new String[]{
"%"+content+"%"}, null, null, null);
if (cursor != null) {
while (cursor.moveToNext()) {
String id = cursor.getString(cursor.getColumnIndexOrThrow("id"));
String content2 = cursor.getString(cursor.getColumnIndexOrThrow("content"));
String createTime = cursor.getString(cursor.getColumnIndexOrThrow("create_time"));
String remind = cursor.getString(cursor.getColumnIndexOrThrow("remind"));
int color = cursor.getInt(cursor.getColumnIndexOrThrow("color"));
int isTop = cursor.getInt(cursor.getColumnIndexOrThrow("isTop"));
Note note = new Note();
note.setId(id);
note.setContent(content2);
note.setCreatedTime(createTime);
note.setRemind(remind);
note.setColor(color);
note.setIsTop(isTop);
noteList.add(note);
}
cursor.close();
}
return noteList;
}
}
6、时间初始化
初始化便签创建的时候(存入数据库数据)以及具体显示在页面上的时间
FormatTime.java
package com.tinno.utils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
/** * 时间工具类 */
public class FormatTime {
// 获取当前时间的方法
public static String getCurrentTimeFormat(){
long currentTime = System.currentTimeMillis();
String timeNow = new SimpleDateFormat("yyyy/MM/dd HH:mm").format(currentTime);
return timeNow;
}
/** * 通过对数据库时间的整理,结合当前的时间,对显示的时间做一个整合 * 时间显示方式 * 1、今天: hh-mm; * 2、昨天: 昨天 hh-mm; * 3、本周内: 周几 hh-mm; * 4、本周之外: nnnn-yy-dd; * @param time 传入数据库存储的时间点 * @return */
public static String FormatTimeForDb(String time){
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm");
Date date2;
date2 = new Date(System.currentTimeMillis());
int year1 = Integer.parseInt(time.substring(0,4));
int month1 = Integer.parseInt(time.substring(5,7));
int day1 = Integer.parseInt(time.substring(8,10));
int h1 = Integer.parseInt(time.substring(11,13));
int m1 = Integer.parseInt(time.substring(14,16));
// 现在的时间
String str2 = simpleDateFormat.format(date2);
int year2 = Integer.parseInt(str2.substring(0, 4));
int month2 = Integer.parseInt(str2.substring(5, 7));
int day2 = Integer.parseInt(str2.substring(8, 10));
int h2 = Integer.parseInt(str2.substring(11, 13));
int m2 = Integer.parseInt(str2.substring(14, 16));
if (year2 > year1) {
return year1 + "/" + time.substring(5, 7) + "/" + time.substring(8, 10);
} else if (month2 > month1) {
return year1 + "/" + time.substring(5, 7) + "/" + time.substring(8, 10);
} else if (day2 > day1) {
if (day2 - day1 == 1){
return "昨天 " + time.substring(11,13) + ":" + time.substring(14,16);
}else if (day2 - day1 < 7){
return getWeek(time) + " " + time.substring(11,13) + ":" + time.substring(14,16);
}else {
return year1 + "/" + time.substring(5, 7) + "/" + time.substring(8, 10);
}
} else {
return "今天 " + time.substring(11, 13) + ":" + time.substring(14, 16);
}
}
/** * 获取指定的时候的周几工具类 * @param dateTime 传入需要变化的具体时间 格式为 yyyy/MM/dd * @return */
private static int getDayofWeek(String dateTime) {
Calendar cal = Calendar.getInstance();
if (dateTime.equals("")) {
cal.setTime(new Date(System.currentTimeMillis()));
} else {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd", Locale.getDefault());
Date date;
try {
date = sdf.parse(dateTime);
} catch (ParseException e) {
date = null;
e.printStackTrace();
}
if (date != null) {
cal.setTime(new Date(date.getTime()));
}
}
return cal.get(Calendar.DAY_OF_WEEK);
}
/** * 将指定时间转化为显示的具体周几 * @param time * @return */
public static String getWeek(String time){
int dayofWeek = getDayofWeek(time);
if (1 == dayofWeek){
return "周日";
}else if (2 == dayofWeek){
return "周一";
}else if (3 ==dayofWeek){
return "周二";
}else if (4 == dayofWeek){
return "周三";
}else if (5==dayofWeek){
return "周四";
}else if (6 == dayofWeek){
return "周五";
}else{
return "周六";
}
}
}
7、便签皮肤展示和修改
使用popupWindow
控件对便签皮肤的效果进行展示,并为每个皮肤设置点击事件,监控点击并更改主题颜色
popupWindow
的布局popup_theme.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">
<LinearLayout android:layout_width="320dp" android:layout_height="80dp" android:orientation="horizontal" android:background="@color/menu_background" android:layout_gravity="end" android:layout_marginTop="10dp" android:layout_marginRight="10dp">
<FrameLayout android:id="@+id/theme1" android:layout_width="60dp" android:layout_height="60dp" android:background="@color/menu_theme1" android:layout_gravity="center" android:layout_margin="10dp"/>
<FrameLayout android:id="@+id/theme2" android:layout_width="60dp" android:layout_height="60dp" android:background="@color/menu_theme2" android:layout_gravity="center" android:layout_margin="10dp"/>
<FrameLayout android:id="@+id/theme3" android:layout_width="60dp" android:layout_height="60dp" android:background="@color/menu_theme3" android:layout_gravity="center" android:layout_margin="10dp"/>
<FrameLayout android:id="@+id/theme4" android:layout_width="60dp" android:layout_height="60dp" android:background="@color/menu_theme4" android:layout_gravity="center" android:layout_margin="10dp"/>
</LinearLayout>
</LinearLayout>
效果:
代码实现:
// popupWindow的控件和显示
public void showPopupWindow(View view){
View popupView = getLayoutInflater().inflate(R.layout.popup_theme,null);
FrameLayout btn1,btn2,btn3,btn4;
btn1 = popupView.findViewById(R.id.theme1);
btn2 = popupView.findViewById(R.id.theme2);
btn3 = popupView.findViewById(R.id.theme3);
btn4 = popupView.findViewById(R.id.theme4);
PopupWindow popupWindow = new PopupWindow(popupView, ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT,true);
popupWindow.showAsDropDown(edit_themes);
btn1.setOnClickListener(view1 -> {
content_container.setBackgroundColor(Color.parseColor("#BFC8FD"));
edit_themes.setBackgroundColor(Color.parseColor("#BFC8FD"));
Log.d(TAG, "showPopupWindow: 颜色");
popupWindow.dismiss();
});
btn2.setOnClickListener(view1 -> {
content_container.setBackgroundColor(Color.parseColor("#A5EEE5"));
edit_themes.setBackgroundColor(Color.parseColor("#A5EEE5"));
popupWindow.dismiss();
});
btn3.setOnClickListener(view1 -> {
content_container.setBackgroundColor(Color.parseColor("#FCBEBE"));
edit_themes.setBackgroundColor(Color.parseColor("#FCBEBE"));
popupWindow.dismiss();
});
btn4.setOnClickListener(view1 -> {
content_container.setBackgroundColor(Color.parseColor("#FFF195"));
edit_themes.setBackgroundColor(Color.parseColor("#FFF195"));
popupWindow.dismiss();
});
}
8、时间和日期选择器
在编辑和新增页面中,点击闹钟按钮,添加提醒时间,弹出3个dialog,第一个是便签提醒文字,点击确认弹出日期选择器,选择日期后,上面的日期框出现选中的日期,在点击确认按钮,弹出时间选择器,点击确认市,上面的textView出现选择的日期和时间。
先为日期和时间选择器完成一个布局,在基于这个布局进行一个dialog的弹窗实现
dialog_date_select.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center_horizontal" android:gravity="center_horizontal">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/set_alarm_title" android:textStyle="bold" android:textSize="20sp" android:typeface="serif" android:layout_marginTop="5dp" android:textColor="@color/black"/>
<LinearLayout android:layout_width="match_parent" android:layout_height="30dp" android:gravity="center">
<TextView android:id="@+id/dds_time" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:text="时间(10:55)" android:textSize="16sp" android:layout_weight="1" />
<TextView android:id="@+id/dds_date" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:text="日期(06/27)" android:layout_weight="1" android:textSize="16sp" />
</LinearLayout>
<DatePicker android:id="@+id/date_picker" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:spinnersShown="false" />
<TimePicker android:id="@+id/time_picker" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dp" />
</LinearLayout>
效果:
实现代码
// 弹出一个dialog
public void showDialog(){
final EditText message = new EditText(this);
message.setPadding(10,10,10,10);
message.setTextColor(Color.BLACK);
message.setBackgroundColor(Color.WHITE);
TextView title = new TextView(this);
title.setText("便签提醒");
title.setPadding(10,10,10,10);
title.setGravity(Gravity.CENTER);
title.setTextColor(Color.BLACK);
title.setTextSize(26);
title.setBackgroundColor(Color.parseColor("#F2F2F2"));
AlertDialog dialog = new AlertDialog.Builder(this)
.setView(message)
.setCustomTitle(title)
.setNeutralButton("进入便签", null)
.setPositiveButton("确认",null)
.create();
dialog.show();
// 进入便签按钮
dialog.getButton(AlertDialog.BUTTON_NEUTRAL).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dialog.dismiss();
}
});
// 确定按钮
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(context, "获取输入框的内容:" + message.getText().toString(), Toast.LENGTH_SHORT).show();
showDate();
//Toast.makeText(context, "确认按钮", Toast.LENGTH_SHORT).show();
}
});
}
// 初始化日期和时间选择器布局
public void initShowDateView(){
v = View.inflate(context,R.layout.dialog_date_select,null);
datePicker = (DatePicker) v.findViewById(R.id.date_picker);
timePicker = (TimePicker) v.findViewById(R.id.time_picker);
ddsDate = (TextView) v.findViewById(R.id.dds_date);
ddsTime = (TextView) v.findViewById(R.id.dds_time);
}
// 日期选择器
public void showDate(){
// 初始化控件
initShowDateView();
// 移除此处不需要的时间选择控件
((ViewGroup)v).removeView(timePicker);
AlertDialog alertDialog = new AlertDialog.Builder(context)
.setView(v)
.setNeutralButton(getString(R.string.cancel),null)
.setPositiveButton(getString(R.string.sure),null)
.create();
alertDialog.show();
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
year = calendar.get(Calendar.YEAR);
month = calendar.get(Calendar.MONTH);
day = calendar.get(Calendar.DAY_OF_MONTH);
/** * //初始化日期选择器并设置日期改变监听器 * datePicker.init(year, month, day, new DatePicker.OnDateChangedListener() { * @Override * public void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth) { * //获取选中的年月日 * DataPickerActivity.this.year = year; * //月份是从0开始的 * DataPickerActivity.this.month = (monthOfYear+1); * DataPickerActivity.this.day = dayOfMonth; * //弹窗显示 * Toast.makeText(DataPickerActivity.this,DataPickerActivity.this.year+"年"+DataPickerActivity.this.month+"月"+DataPickerActivity.this.day+"日",Toast.LENGTH_SHORT).show(); * } * }); */
// 设置监听器,监听数据改变
datePicker.init(year, month, day, (datePicker1, i, i1, i2) -> {
this.year = i;
this.month = i1 + 1;
this.day = i2;
//Toast.makeText(context, "i=>" + i + "<=> i1 <=>" + i1 + "<=> i2 <=>" + i2, Toast.LENGTH_SHORT).show();
//Toast.makeText(context, year + "/" + month + "/" + day, Toast.LENGTH_SHORT).show();
ddsDate.setText(year+"/"+month+"/"+day);
//EditNoteActivity.this.ddsDate.setText(dateStr);
});
//Toast.makeText(EditNoteActivity.this, year + "/" + month + "/" + day, Toast.LENGTH_SHORT).show();
alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL).setOnClickListener(view -> {
alertDialog.dismiss();
});
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(view -> {
showTime();
//Toast.makeText(context, "时间选择器", Toast.LENGTH_SHORT).show();
});
}
// 时间选择器
public void showTime(){
initShowDateView();
// 移除时间选择器和日期选择器在添加时间选择器
((ViewGroup)v).removeView(datePicker);
((ViewGroup)v).removeView(timePicker);
((ViewGroup)v).addView(timePicker);
AlertDialog dialog = new AlertDialog.Builder(context)
.setView(v)
.setNeutralButton(getString(R.string.cancel),null)
.setPositiveButton(getString(R.string.sure),null)
.create();
dialog.show();
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
timePicker.setIs24HourView(true);
timePicker.setCurrentHour(calendar.get(Calendar.HOUR_OF_DAY));
timePicker.setCurrentMinute(Calendar.MINUTE);
// 取消按钮
dialog.getButton(AlertDialog.BUTTON_NEUTRAL).setOnClickListener(view -> {
dialog.dismiss();
});
//确认按钮
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(view -> {
String CurrentHour = timePicker.getCurrentHour().toString();
String CurrentMinute = timePicker.getCurrentMinute().toString();
if (timePicker.getCurrentHour() >= 0 && timePicker.getCurrentHour() <= 9) {
CurrentHour = "0" + timePicker.getCurrentHour() ;
}
if (timePicker.getCurrentMinute() >= 0 && timePicker.getCurrentMinute() <= 9) {
CurrentMinute = "0" + timePicker.getCurrentMinute();
}
StringBuffer sb = new StringBuffer();
sb.append(String.format("%d/%02d/%02d",
datePicker.getYear(),
datePicker.getMonth() + 1,
datePicker.getDayOfMonth()));
sb.append(" ");
sb.append(CurrentHour)
.append(":")
.append(CurrentMinute);
String ttime = sb.toString();
String[] s = ttime.split(" ");
//Toast.makeText(context, Arrays.toString(s), Toast.LENGTH_SHORT).show();
//Toast.makeText(context, "date ==> "+ s[0] + "<==> time ==> " + s[1], Toast.LENGTH_SHORT).show();
// 将日期和时间进行切割,并将对应的值复制到对应的控件上
ddsDate.setText(s[0]);
ddsTime.setText(s[1]);
Note n = new Note();
n.setId(note.getId());
n.setCreatedTime(note.getCreatedTime());
n.setColor(note.getColor());
n.setContent(note.getContent());
n.setIsTop(note.getIsTop());
n.setRemind(ttime);
Log.d(TAG, "获取的值 : " + n);
mNoteDbHelper = new NoteDbHelper(this);
mNoteDbHelper.updateData(n);
finish();
});
}
9、长按编辑功能
在主页中,长按某一个item,出现四个编辑按钮和多选按钮,可以对主页便签进行顶置、删除等功能
删除功能
实现代码:
首先对长按后的一个控件显示和隐藏功能
@Override public void onBindViewHolder(@NonNull RecyclerViewHolder holder, int position) { Note note = mBeanList.get(position); holder.mTvCreateTime.setText(FormatTime.FormatTimeForDb(note.getCreatedTime())); holder.mTvContent.setText(note.getContent()); holder.lrContainer.setBackgroundColor(note.getColor()); // 为控件设置长按点击事件 holder.lrContainer.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View view) { //对flag进行一个自增,当flag从开始点击的时候,当flag是2的除数的时候,showIcon设置false,反之设为true; flag++; Log.d(TAG, "showIcon " + showIcon); // 设置一个全部变量,使长按点击的时候,状态变为true,并调用 notifyItemRangeChanged(int positionStart,int itemCount)方法进行从指定位置刷新,刷新多少个 //Toast.makeText(mContext, "showIcon的状态" + showIcon, Toast.LENGTH_SHORT).show(); if (flag % 2 == 0 ){ showIcon = false; }else { showIcon = true; } showOrHide(showIcon); //Toast.makeText(mContext, "获取该item的id" + mBeanList.get(position), Toast.LENGTH_SHORT).show(); notifyItemRangeChanged(0,mBeanList.size()); return true; } }); // 判断showIcon的状态是否为true,为true的时候,checkbox显示,反正则隐藏 holder.mCheckBox.setVisibility(showIcon ? VISIBLE : View.GONE); ...... ...... ...... }
// 获取MainActivity中的控件,并对该控件进行显示和隐藏 public void showOrHide(boolean isShow){ mNoteAdd = ((MainActivity) mContext).findViewById(R.id.id_note_add); mNoteBottom = ((MainActivity) mContext).findViewById(R.id.id_note_bottom); noteToolbar = ((MainActivity) mContext).findViewById(R.id.id_note_toolbar); if (isShow){ mNoteAdd.setVisibility(View.GONE); mNoteBottom.setVisibility(VISIBLE); noteToolbar.setVisibility(VISIBLE); }else { mNoteAdd.setVisibility(VISIBLE); mNoteBottom.setVisibility(View.GONE); noteToolbar.setVisibility(View.GONE); } }
在
RecyclerAdapter
中自定义一个接口,用来接收多选框的点击事件。public class RecyclerViewHolder extends RecyclerView.ViewHolder { private TextView mTvCreateTime; private TextView mTvContent; private ImageView mTvRemind,mIvTopTab; private ViewGroup lrContainer; private LinearLayout recycler_background; private CheckBox mCheckBox; public RecyclerViewHolder(@NonNull View itemView) { super(itemView); mTvCreateTime = itemView.findViewById(R.id.tv_time); mTvContent = itemView.findViewById(R.id.tv_content); mTvRemind = itemView.findViewById(R.id.iv_remind); lrContainer = itemView.findViewById(R.id.lr_list_container); mCheckBox = itemView.findViewById(R.id.checkbox); recycler_background = itemView.findViewById(R.id.recycler_background); mIvTopTab = itemView.findViewById(R.id.iv_topTab); // 多选框的点击事件 mCheckBox.setOnClickListener(view -> { if (mCheckBox.isChecked()){ mOnItemClickListener.onRecyclerItemClick(getAdapterPosition()); } }); } } private OnRecyclerItemClickListener mOnItemClickListener; //设置监听的方法 public void setRecyclerItemClickListener(OnRecyclerItemClickListener listener){ mOnItemClickListener = listener; } //自定义设置一个监听器 public interface OnRecyclerItemClickListener{ void onRecyclerItemClick(int position); }
在
MainActivity.java
中获取 RecyclerView中CheckBox的选择框内容// 获取RecyclerView中checkBox的选择框内容 public void show(){ list = new ArrayList<>(); mRecyclerAdapter.setRecyclerItemClickListener(position -> { list.add(data.get(position).getId()); Log.d(TAG, "show: " + list); //Toast.makeText(mContext, "是否顶置" + data.get(position).getIsTop(), Toast.LENGTH_SHORT).show(); if (data.get(position).getIsTop() == 1){ Toast.makeText(mContext, "是否取消顶置", Toast.LENGTH_SHORT).show(); tvHeaderTop.setText("取消顶置"); }else { Toast.makeText(mContext, "是否顶置", Toast.LENGTH_SHORT).show(); tvHeaderTop.setText("顶置"); } });
返回主页的一个原始状态
// 返回至主页的完美状态 public void showHome(){ RecyclerAdapter adapter = new RecyclerAdapter(mContext,data); adapter.showOrHide(false); onResume(); }
在点击按钮中,调用方法,获取点击的checkbox的数据id,进行一个数据删除
@Override
public void onClick(View view) {
switch (view.getId()){
....
....
case R.id.header_delete:
for (String s : list) {
mNoteDbHelper.deleteFromDbById(s);
}
showHome()
break;
}
}
顶置功能
实现代码
@Override
public void onBindViewHolder(@NonNull RecyclerViewHolder holder, int position) {
Note note = mBeanList.get(position);
holder.mTvCreateTime.setText(FormatTime.FormatTimeForDb(note.getCreatedTime()));
holder.mTvContent.setText(note.getContent());
holder.lrContainer.setBackgroundColor(note.getColor());
......
......
......
// 为顶置便签内容设置顶置标签
if (noteList.get(position).getIsTop() == 1){
holder.mIvTopTab.setVisibility(VISIBLE);
}else if (noteList.get(position).getIsTop() == 0){
holder.mIvTopTab.setVisibility(View.INVISIBLE);
}
}
// 设置便签顶置事件
public void setThingTop(){
// 对从数据库查询到所有的数组内容进行遍历
for (Note datum : data) {
Log.d(TAG, "onClick: " + datum);
// 对checkbox点击事件进行遍历,获取id
for (String noteId : list){
// 判断数据库的id和checkbox获取内容的id是否相等,相等则进行下一步操作
if (datum.getId().equals(noteId)){
Log.d(TAG, "onClick: -------------------------------------------");
Log.d(TAG, "获取的事件: " + datum.getContent() + "=>" + datum.getId());
Note n = new Note();
n.setId(datum.getId());
n.setContent(datum.getContent());
n.setRemind(datum.getRemind());
n.setColor(datum.getColor());
n.setCreatedTime(datum.getCreatedTime());
if (tvHeaderTop.getText().toString().equals("顶置")){
n.setIsTop(1);
}else if (tvHeaderTop.getText().toString().equals("取消顶置")){
n.setIsTop(0);
}
mNoteDbHelper.updateData(n);
Log.d(TAG, "获取新的Note对象:" + n);
Log.d(TAG, "onClick: ---------------------------------------------" );
}
}
}
}
@Override
public void onClick(View view) {
switch (view.getId()){
....
....
case R.id.header_top:
setThingTop();
showHome();
break;
....
....
}
}
10、为主页中的便签设置了闹钟功能的便签显示一个小闹钟图标
在
RecyclerAdapter
@Override public void onBindViewHolder(@NonNull RecyclerViewHolder holder, int position) { Note note = mBeanList.get(position); holder.mTvCreateTime.setText(FormatTime.FormatTimeForDb(note.getCreatedTime())); holder.mTvContent.setText(note.getContent()); holder.lrContainer.setBackgroundColor(note.getColor()); ...... ...... ...... // 判断是否设置了闹钟提醒时间,若没有设置提醒时间,闹钟图标进行隐藏 NoteDbHelper noteDbHelper = new NoteDbHelper(mContext); List<Note> noteList = noteDbHelper.queryAllFromDb(); if (TextUtils.isEmpty(noteList.get(position).getRemind())){ //Log.d(TAG, "onBindViewHolder: " + 123); holder.mTvRemind.setVisibility(View.GONE); }else { holder.mTvRemind.setVisibility(VISIBLE); holder.mTvRemind.setOnClickListener(view -> { showDialog(noteList.get(position).getRemind()); }); } ...... ...... ...... }
// 点击闹钟图标,弹出一个dialog,用来显示提示的内容和提示的时间 public void showDialog(String str){ AlertDialog dialog = new AlertDialog.Builder(mContext) .setTitle("事件提醒") .setMessage(str + "\n" + str) .create(); dialog.show(); }
效果
整体的代码(Demo)
边栏推荐
- CPI tutorial - asynchronous interface creation and use
- Consolidate -c operator
- GPS 数据中的精度因子(DOP)与协方差之间的关系 (参考链接)
- [MCU] [nixie tube] nixie tube display
- (混更一篇)多个txt文本转一个表格
- STM32 project practice (1) introduction and use of photosensitive resistor
- uniapp 使用 uni-upgrade-center
- GID: open vision proposes a comprehensive detection model knowledge distillation | CVPR 2021
- Circular linked list--
- Switch basic experiment
猜你喜欢
顺序表有关操作
Ipv6-6to4 experiment
Double linked list related operations
Circular linked list--
[106] 360 check font - check whether the copyright of local Fonts is commercially available
91. (cesium chapter) cesium rocket launch simulation
Queue operation---
BIM and safety in road maintenance-buildSmart Spain
Sort out relevant contents of ansible
Ansible相关内容梳理
随机推荐
队列的链式存储
Onenet Internet of things platform - the console sends commands to mqtt product devices
MySQL common functions
[Yunju entrepreneurial foundation notes] Chapter VII Entrepreneurial Resource test 1
Pandas reads MySQL data
Le semester manquant
[Maui] add click events for label, image and other controls
Implementation of address book management system with C language
STM32 project practice (1) introduction and use of photosensitive resistor
Chained storage of queues
Dlhsoft Kanban, Kanban component of WPF
二叉树的链式存储
使用BurpSuite对app抓包教程
Build yocto system offline for i.mx8mmini development board
AI抠图工具
【语音信号处理】3语音信号可视化——prosody
【datawhale202206】pyTorch推荐系统:多任务学习 ESMM&MMOE
第十四章 信号(四)- 多进程任务示例
编译调试Net6源码
Consolidate -c operator