android wear OS 记事本

Android系统穿戴设备开发:Wear OS最佳实践 本文旨在为Android开发者提供全面的Wear OS开发指南,涵盖从基础概念到高级优化的所有关键方面。我们将重点讨论Wear OS特有的开发模式和最佳实践,帮助开发者构建高效、用户友好的穿戴设备应用。文章将从Wear OS架构开始,逐步深入到具体实现和优化策略。我们将提供大量代码示例和实际案例,确保读者能够将所学知识立即应用到实际项目中。Wear OS: Google专为穿戴设备设计的操作系统: 表盘上显示的小型信息组件Tiles: 可滑动浏览的信息卡片集合: 低功耗显示模式发展趋势。 阅读详情

android-wear os 记事本开发

wear-OS 记事本

sqllite+recyclerview的基本使用

一、创建项目

新建项目,选择wear,点击默认的activity,而后点击next,起好自己的项目名称创建
在这里插入图片描述

二、构建activity,继承wearableactivity

等待构建、activity继承自wearableActivity,
在这里插入图片描述

三、根布局适配

根布局使用BoxInsetLayout,直接子布局用app:boxedEdges="all"这个属性,一般来说不会报错,报红也没事,运行没有问题。

这里的意思是适配方形的手表和圆形的手表,当手表是圆形的时候,内容将全部现实于圆心,具体图片我就不展示了。
在这里插入图片描述

四、添加列表视图

主界面放一个列表视图用于展示笔记条目,也就是数据库里面的内容
WearableRecyclerView,这个在wear项目中等同于android的recyclerview。
在这里插入图片描述

五、跳转按钮

屏幕添加一个按钮,点击进入笔记编辑页面
ps:按理说手表小,应该手势操作滑动进入,但是我这里使用gesture没有效果,emmm,应为我是昨天才开始看wear的,也没找到什么资料,暂时不会解决。睡会解决的话麻烦告知一下谢谢

六、创建不同类别的包

创建四个包,分别存放不同的类(当然不创建也可以,个人觉得这样较为清楚)
在这里插入图片描述

七、创建第二个activity

创建第二个activity,也就是添加日记的页面,一般来说我是直接右键系统自动生成activity,但这里要继承wear的类,我直接复制并改名,(layout文件也要复制哦),记得activity必须要在清单文件中注册
在这里插入图片描述

八、完善主页布局文件,添加了一个swiperefresh

完成mainactivity的xml布局,该布局中我在根布局-----》fragment-----》下添加了Swiperefreshlayout布局,用于进行数据的刷新。因为在wear下我采取生命周期的方法让适配器在发生数据变化时刷新无效,所以采用下拉刷新控件,在swiperefresh下放一个相对布局,在相对布局中放置一个wearablerecyclerview控件进行数据库内容的映射,也就是日记列表面,然后添加一个进行页面跳转的控件,这里我添加了img,让其位于父控件的右底部。

布局层次如下,img与列表控件同级
boxinsetlayout——>FrameLayout——》SwipeRefreshLayout——》RelativeLayout——》WearableRecyclerView+imageview
在这里插入图片描述

九、日记编写页面的搭建

注意:外部的scrollview视图添加,方面页面过大导致界面出问题,原本是通过手势检测进行一个右边的控制面板的构建,手势滑动将其显示,结果因为gesture在wear没有效果(我这边无效),就弃用了,后面也适用了drawablelayout,体验并不怎么好,也启用。所以通过滚动视图将其置于输入框的下边
在这里插入图片描述

在这里插入图片描述

十、常量类的创建

我们计划的数据库有库名,表名,还有三个字段,分别是id,内容,时间,id用于删改查,其他自然是信息了。故此我们进行常量的设定
在这里插入图片描述
同时设置一个获取当前系统时间的方法,并返回格式的文本

在这里插入图片描述
本来设置了一个吐司提示调用的方法,但是android原生态吐司在wear中太难看了,我后面没有用到,想加的可以加

该类代码如下

package com.yangpeilin.aaa.Constant;

import android.annotation.SuppressLint;
import android.content.Context;
import android.widget.Toast;

import java.text.SimpleDateFormat;
import java.util.Date;

public class Constant {
    /**
     * id
     * 内容
     * 时间
     * 表名
     * 数据库
     */
    public static final String ID = "node_id";
    public static final String CONTEXT = "node_context";
    public static final String TIME = "node_time";
    public static final String TABLENAME = "node";
    public static final String DBNAME = "node.db";

//    获取当前时间并格式化
    public static String getTime(){
        Date date = new Date();
        @SuppressLint("SimpleDateFormat") SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
        String format = dateFormat.format(date);
        return format;
    }

//    吐司提示
    public static void showMsg(String msg, Context context){
        Toast.makeText(context,msg,Toast.LENGTH_SHORT).show();
    }
}

十一、实体类的创建

我们便于数据的操作,来创建一个bean类,同时创建出她的无参构造和全参构造,并实现get/set方法,代码如下

package com.yangpeilin.aaa.Bean;

/**
 * 实体类
 */
public class NodeBean {

    private String id;
    private String context;
    private String time;

    public NodeBean() {
    }

    public NodeBean(String id, String context, String time) {
        this.id = id;
        this.context = context;
        this.time = time;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getContext() {
        return context;
    }

    public void setContext(String context) {
        this.context = context;
    }

    public String getTime() {
        return time;
    }

    public void setTime(String time) {
        this.time = time;
    }
}

十二、数据库的操作

我这里将数据库的创建以及帮助类操作方法放在了一起。
我们创建一个数据库,工厂不用,给个null,版本为1。
我们在构造方法中直接得到database帮助类,并将其抽取为全局变量
在这里插入图片描述
创建数据表,三个字段,id为integer类型,主键自增,其他两个设置为text类型即可,varchar 也可以。

"create table node(node_id integer primary key autoincrement,node_context text,node_time text)"

实现增删改查的方法,增需要values,改需要values id 删需要id 查需要游标、集合。我们将查询到的数据直接通过一个集合返回。这都是sqlite的基本api,这里不做细说。

  • 增删改查对应
  • insert delete update queryall
  • 该类整体代码如下
package com.yangpeilin.aaa.SQLHelper;

import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import androidx.annotation.Nullable;

import com.yangpeilin.aaa.Bean.NodeBean;
import com.yangpeilin.aaa.Constant.Constant;

import java.util.ArrayList;
import java.util.List;

public class MySQLHelper extends SQLiteOpenHelper {

    private final SQLiteDatabase database;
    private final String createTable
            = "create table node(node_id integer primary key autoincrement,node_context text,node_time text)";

    /**
     *
     * @param context  上下文
     * @param //name      数据库
     * @param //factory   工厂
     * @param //version    版本号
     */
    public MySQLHelper(@Nullable Context context) {
        super(context, Constant.DBNAME, null, 1);
//        实例化该类时就创建database操作
//        getWritableDatabase同样可以进行读取
        database = this.getWritableDatabase();
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(createTable);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }

    /**
     * 增删改查
     * insert delete update queryall
     */
    public void insert(String context,String time){
        ContentValues values = new ContentValues();
        values.put(Constant.CONTEXT,context);
        values.put(Constant.TIME,time);
        database.insert(Constant.TABLENAME, null, values);
//        操作完关闭
        database.close();
    }
    public void update(String context,String time,String id){
        ContentValues values = new ContentValues();
        values.put(Constant.CONTEXT,context);
        values.put(Constant.TIME,time);
        database.update(Constant.TABLENAME, values,"node_id=?",new String[]{id});
//        操作完关闭
        database.close();
    }
    public void delete(String id){
        database.delete(Constant.TABLENAME,"node_id=?",new String[]{id});
//        操作完关闭
        database.close();
    }

    public List<NodeBean> queryAll(){
        @SuppressLint("Recycle") Cursor cursor = database.rawQuery("select * from node", null);
        List<NodeBean> list = new ArrayList<>();
        while (cursor.moveToNext()) {
            int id = cursor.getInt(cursor.getColumnIndex(Constant.ID));
            String context = cursor.getString(cursor.getColumnIndex(Constant.CONTEXT));
            String time = cursor.getString(cursor.getColumnIndex(Constant.TIME));
            NodeBean bean = new NodeBean(String.valueOf(id),context,time);
            list.add(bean);
        }
        cursor.close();
        database.close();
        return list;
    }
}

十三、编写自定义alterdialog

布局不做赘述,直接贴代码
在这里插入图片描述

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    android:layout_height="wrap_content">
<LinearLayout
    android:orientation="vertical"
    android:layout_width="100dp"
    android:layout_height="80dp">
    <TextView
        android:text="@string/delete"
        android:gravity="center"
        android:textStyle="bold"
        android:textSize="20sp"
        android:textColor="@color/white"
        android:layout_width="match_parent"
        android:layout_height="50dp"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <TextView android:gravity="center"
            android:id="@+id/tv_delete_yes"
            android:textStyle="bold"
            android:textSize="16sp"
            android:layout_weight="1"
            android:text="@string/yes"
            android:layout_width="0dp"
            android:layout_height="match_parent"/>
        <TextView android:gravity="center"
            android:id="@+id/tv_delete_no"
            android:textStyle="bold"
            android:textSize="16sp"
            android:layout_weight="1"
            android:text="@string/no"
            android:layout_width="0dp"
            android:layout_height="match_parent"/>
    </LinearLayout>
</LinearLayout>
</LinearLayout>

十四、列表条目布局文件的编写

该布局中就两个文本,一个用于显示title,一个用于显示时间
代码如下

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:orientation="vertical"
    android:layout_marginBottom="1px"
    android:layout_height="wrap_content">
<TextView
    android:id="@+id/item_title"
    android:lines="1"
    android:enabled="true"
    android:textSize="10sp"
    android:textColor="@color/white"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>
    <TextView
        android:textColor="@color/white"
        android:id="@+id/item_time"
        android:textSize="6sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    <View
        android:layout_marginTop="1dp"
        android:background="#ffffff"
        android:layout_width="match_parent"
        android:layout_height="1px"/>
</LinearLayout>

十五、编写适配器

wearablerecyclerview使用的适配器与recyclerview适配器相同
需要两个成员变量,一个上下文,一个集合
适配器的编写不做介绍
不知为何通过接口再activity中调用不到点击事件,莫不是被消化了?这里的点击事件我们直接在适配器中操作

长按弹出提示框,删除条目选项
点击跳转到详情页面,同时传递参数,用于判断是修改还是删除

完整代码如下

package com.yangpeilin.aaa.Adapter;

import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.yangpeilin.aaa.Bean.NodeBean;
import com.yangpeilin.aaa.MainActivity;
import com.yangpeilin.aaa.R;
import com.yangpeilin.aaa.SQLHelper.MySQLHelper;
import com.yangpeilin.aaa.SecondActivity;

import java.util.ArrayList;
import java.util.List;

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyHolder> {
    Context context;
    List<NodeBean> list = new ArrayList<>();
    public MyAdapter(Context context) {
        this.context = context;
    }

    public void addList(List<NodeBean> list) {
        this.list = list;
        notifyDataSetChanged();
    }

   /* AdapteronClick adapteronClick;
    public interface AdapteronClick{
        void shortClick(String id,String tite,String time);
        void longClick(String id,String tite,String time);
    }

    public void setOnItemClickListener(AdapteronClick adapteronClick) {
        adapteronClick = adapteronClick;
    }*/

    @NonNull
    @Override
    public MyHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new MyHolder(LayoutInflater.from(context).inflate(R.layout.item,parent,false));
    }

    @Override
    public void onBindViewHolder(@NonNull MyHolder holder, int position) {
        final NodeBean bean = list.get(position);
        holder.title.setText(bean.getContext());
        holder.time.setText(bean.getTime());
//        条目点击事件
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d("TAGAdapter", "onClick: ");
                Intent intent = new Intent(context, SecondActivity.class);
                intent.putExtra("id",bean.getId());
                intent.putExtra("tite", bean.getContext());
                Log.d("TAG", "shortClick: \n点击条目进入");
                Log.d("TAG", "shortClick: \n"+bean.getContext()+"\n"+bean.getId());
                context.startActivity(intent);
            }
        });
        holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {

                AlertDialog.Builder builder = new AlertDialog.Builder(context);
                final AlertDialog alertDialog = builder.create();
                View inflate = View.inflate(context, R.layout.dialog_item, null);
                alertDialog.setView(inflate);
                alertDialog.show();
                inflate.findViewById(R.id.tv_delete_no).setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        alertDialog.dismiss();
                    }
                });
                inflate.findViewById(R.id.tv_delete_yes).setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        MySQLHelper helper = new MySQLHelper(context);
                        helper.delete(bean.getId());
                        Log.d("TAG", "onClick: 删除成功");
                        MyAdapter.this.notifyDataSetChanged();
                        alertDialog.dismiss();
                    }
                });
                /*Log.d("TAG", "onLongClick: ");
                if (adapteronClick!=null) {
                    adapteronClick.longClick(bean.getId(),bean.getContext(),bean.getTime());
                Log.d("TAG", "onLongClick: ");
                }*/
//                消化事件
                return true;
            }
        });
    }

    @Override
    public int getItemCount() {
        return list.size()>0?list.size():0;
    }

    class MyHolder extends RecyclerView.ViewHolder{

        private final TextView title;
        private final TextView time;

        public MyHolder(@NonNull View itemView) {
            super(itemView);
            title = itemView.findViewById(R.id.item_title);
            time = itemView.findViewById(R.id.item_time);
        }
    }
}

十六 mainactivity 主界面的编写

主界面编写就简单了,初始化控件,调用SQL的查询方法,返回集合,实例化适配器,给适配器传入数据,给列表条目设置适配器。 设置swiperefresh下拉刷新控件的方法,刷新时重新获取数据并展示,返回false,刷新操作完成后圈圈消化掉。
实现添加按钮的点击操作,点击跳转到日记详情页面
package com.yangpeilin.aaa;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.wearable.activity.WearableActivity;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import androidx.wear.widget.BoxInsetLayout;
import androidx.wear.widget.WearableRecyclerView;

import com.yangpeilin.aaa.Adapter.MyAdapter;
import com.yangpeilin.aaa.Bean.NodeBean;
import com.yangpeilin.aaa.SQLHelper.MySQLHelper;

import java.util.List;

public class MainActivity extends WearableActivity{

    private WearableRecyclerView main_recyclerview;
    private ImageView img_add;
    private Context context;
    private String tag;
    private MyAdapter adapter;
    private SwipeRefreshLayout swiper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tag = getClass().getName();
        // Enables Always-on
        setAmbientEnabled();

//        初始化控件
        initView();
//        监听事件
        imgListener();
//        recyclerview的相关配置以及条目的点击事件
        recyclerInit();


    }


    //    生命周期能执行到,但是刷新不了适配器数据,改用swiperefresh实现
    @Override
    protected void onResume() {
        super.onResume();
        recyclerInit();
        Log.d("TAG", "onResume: \n刷新刷新");
    }

    public void recyclerInit() {
        MySQLHelper helper = new MySQLHelper(this);
        List<NodeBean> list = helper.queryAll();
        main_recyclerview.setLayoutManager(new LinearLayoutManager(this));
        adapter = new MyAdapter(this);
        adapter.addList(list);
        main_recyclerview.setAdapter(adapter);
    }

    private void imgListener() {
        img_add.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(context, SecondActivity.class));
                Log.d(tag, "onClick: \n进入详情页面");
            }
        });
        swiper.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                recyclerInit();
                swiper.setRefreshing(false);
            }
        });
    }

    private void initView() {
        context = MainActivity.this;
        main_recyclerview = findViewById(R.id.main_recyclerview);
        img_add = findViewById(R.id.img_add);
        swiper = findViewById(R.id.swiper);
    }

}

十七、详情页面的逻辑实现

该页面也好实现

首先初始化控件
接收主页面传过来的数据,也就是条目点击进行的跳转时发送的数据,如果是点击添加按钮进行跳转,则没有数据传输。如果有数据传过来,就将传过来的内容自动填充到输入框内由用户进行修改编辑
  Intent intent = getIntent();
        id = intent.getStringExtra("id");
        tite = intent.getStringExtra("tite");
        if (!TextUtils.isEmpty(id)){
            node_et_context.setText(tite);
        }
使用activity的生命周期,在用户滑动退出时,也就是失去焦点,不可见,销毁时调用SQL的添加方法,自动保存用户的内容。当然,在在方法内判断传过来的id是否为空,如果为空,执行添加事件,如果不为空,则根据id进行数据库的修改操作。
        if (!TextUtils.isEmpty(trim)) {
            if (TextUtils.isEmpty(id)) {
//                id为空表示点击添加按钮进来的,实施增的做法
                helper.insert(trim, Constant.getTime());
                Log.d("TAG", "onStop: \n我再"+Constant.getTime()+"保存了"+trim);
            }else {
                helper.update(trim,Constant.getTime(),id);
                Log.d("TAG", "onStop: \n我再"+Constant.getTime()+"更新了"+tite+"、变成了"+trim);
            }
        }else {
            Log.d("TAG", "onStop: \n没东西,保存个大西瓜");
        }

    }
定义一个静态变量,进行字号的大小调整,完成加大字体和减小字体的逻辑功能
实现字体颜色切换的功能
package com.yangpeilin.aaa;

import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.support.wearable.activity.WearableActivity;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;

import androidx.wear.widget.SwipeDismissFrameLayout;

import com.yangpeilin.aaa.Constant.Constant;
import com.yangpeilin.aaa.SQLHelper.MySQLHelper;

import java.sql.Time;

public class SecondActivity extends WearableActivity implements View.OnClickListener {


    private EditText node_et_context;
    private ImageView img_big;
    private ImageView img_small;
    private ImageView img_red;
    private ImageView img_black;
    private SwipeDismissFrameLayout swipe;
    private static int FONT_SIZE = 12;
    private String id;
    private String tite;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        // Enables Always-on
        setAmbientEnabled();



//        初始化控件
        initView();
//        监听事件
        mClick();
        //        获取点击条目进入的数据
        Intent intent = getIntent();
        id = intent.getStringExtra("id");
        tite = intent.getStringExtra("tite");
        if (!TextUtils.isEmpty(id)){
            node_et_context.setText(tite);
        }
    }

//    用swipedismiss右滑状态保存的话,在圆形界面,手指沿着左侧划出的话会执行不到他的onDismissed监听方法,
//    而是直接被wear的基层覆盖,用其他两个方法的话存在用户手误状态下退出,所以这里才用onstop生命周期,当用户回退时
    //执行保存的方法
    @Override
    protected void onStop() {
        super.onStop();
        MySQLHelper helper = new MySQLHelper(this);
        String trim = node_et_context.getText().toString().trim();
        if (!TextUtils.isEmpty(trim)) {
            if (TextUtils.isEmpty(id)) {
//                id为空表示点击添加按钮进来的,实施增的做法
                helper.insert(trim, Constant.getTime());
                Log.d("TAG", "onStop: \n我再"+Constant.getTime()+"保存了"+trim);
            }else {
                helper.update(trim,Constant.getTime(),id);
                Log.d("TAG", "onStop: \n我再"+Constant.getTime()+"更新了"+tite+"、变成了"+trim);
            }
        }else {
            Log.d("TAG", "onStop: \n没东西,保存个大西瓜");
        }

    }

    private void mClick() {
        img_big.setOnClickListener(this);
        img_black.setOnClickListener(this);
        img_red.setOnClickListener(this);
        img_small.setOnClickListener(this);
      /*  swipe.addCallback(new SwipeDismissFrameLayout.Callback() {
            @Override
            public void onSwipeStarted(SwipeDismissFrameLayout layout) {
                super.onSwipeStarted(layout);
                Log.d("TAG", "onSwipeStarted: ");
            }

            @Override
            public void onSwipeCanceled(SwipeDismissFrameLayout layout) {
                super.onSwipeCanceled(layout);
                Log.d("TAG", "onSwipeCanceled: ");
            }

            @Override
            public void onDismissed(SwipeDismissFrameLayout layout) {
                super.onDismissed(layout);
                Log.d("TAG", "onDismissed: \n我保存了");
                finish();
                Log.d("TAG", "onDismissed: ");
            }
        });*/
    }

    private void initView() {
        node_et_context = findViewById(R.id.node_et_context);
        img_big = findViewById(R.id.img_big);
        img_small = findViewById(R.id.img_small);
        img_red = findViewById(R.id.img_red);
        img_black = findViewById(R.id.img_black);
        swipe = findViewById(R.id.swipe);
    }

    @Override
    public void onClick(View v) {
        int i;
        switch (v.getId()) {
            case R.id.img_big:
                 i = FONT_SIZE += 2;
                node_et_context.setTextSize(i);
                break;
            case R.id.img_small:
                 i = FONT_SIZE -=2;
                 node_et_context.setTextSize(i);
                break;
            case R.id.img_red:
                node_et_context.setTextColor(Color.parseColor("#ff0000"));
                break;
            case R.id.img_black:
                node_et_context.setTextColor(Color.parseColor("#000000"));
                break;
        }
    }
}

十八、主界面xml文件代码

<?xml version="1.0" encoding="utf-8"?>
<androidx.wear.widget.BoxInsetLayout
    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:id="@+id/fm"
    android:background="@color/dark_grey"
    tools:context=".MainActivity"
    tools:deviceIds="wear">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:boxedEdges="all">

        <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
            android:id="@+id/swiper"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent">
                <androidx.wear.widget.WearableRecyclerView
                    android:id="@+id/main_recyclerview"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"/>
                <ImageView
                    android:id="@+id/img_add"
                    android:layout_alignParentRight="true"
                    android:scaleType="centerCrop"
                    android:layout_alignParentBottom="true"
                    android:background="@drawable/add"
                    android:layout_width="30dp"
                    android:layout_height="30dp"/>
            </RelativeLayout>
        </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

    </FrameLayout>
</androidx.wear.widget.BoxInsetLayout>

十九、日记详情界面xml文件代码

<?xml version="1.0" encoding="utf-8"?>
<androidx.wear.widget.BoxInsetLayout
    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/white"
    tools:deviceIds="wear">

    <FrameLayout
        android:background="@color/white"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:boxedEdges="all">
          <androidx.wear.widget.SwipeDismissFrameLayout
              android:id="@+id/swipe"
              android:layout_width="match_parent"
              android:layout_height="match_parent">
              <ScrollView
                  android:layout_width="match_parent"
                  android:layout_height="match_parent">
                  <RelativeLayout
                      android:layout_width="match_parent"
                      android:layout_height="match_parent">
                      <EditText
                          android:gravity="top"
                          android:id="@+id/node_et_context"
                          android:background="@drawable/border"
                          android:minHeight="120dp"
                          android:textSize="12sp"
                          android:textColor="@color/black"
                          android:textColorHint="@color/black"
                          android:hint="please input context"
                          android:layout_width="match_parent"
                          android:layout_height="wrap_content"/>
                      <LinearLayout
                          android:background="#61000000"
                          android:orientation="vertical"
                          android:layout_width="match_parent"
                          android:layout_below="@id/node_et_context"
                          android:layout_marginTop="3dp"
                          android:layout_height="wrap_content">
                          <LinearLayout
                              android:layout_width="match_parent"
                              android:layout_height="wrap_content">
                              <ImageView
                                  android:id="@+id/img_big"
                                  android:src="@drawable/add"
                                  android:layout_width="0dp"
                                  android:layout_weight="1"
                                  android:layout_height="15dp"/>
                              <ImageView
                                  android:id="@+id/img_small"
                                  android:src="@drawable/sub"
                                  android:layout_width="0dp"
                                  android:layout_weight="1"
                                  android:layout_height="15dp"/>
                          </LinearLayout>
                          <LinearLayout
                              android:layout_width="match_parent"
                              android:layout_height="wrap_content">
                              <ImageView
                                  android:id="@+id/img_red"
                                  android:src="@drawable/red"
                                  android:layout_width="0dp"
                                  android:layout_weight="1"
                                  android:layout_height="15dp"/>
                              <ImageView
                                  android:id="@+id/img_black"
                                  android:src="@drawable/black"
                                  android:layout_width="0dp"
                                  android:layout_weight="1"
                                  android:layout_height="15dp"/>
                          </LinearLayout>
                      </LinearLayout>
                  </RelativeLayout>
              </ScrollView>
          </androidx.wear.widget.SwipeDismissFrameLayout>
    </FrameLayout>
</androidx.wear.widget.BoxInsetLayout>
android wear 开发library android wear开发的 libaray,以library的方式导入即可 立即下载

相关推荐

RcisTarget实战:从差异基因到转录因子调控网络的完整分析流程(附代码)

本文详细介绍了RcisTarget工具在转录因子调控网络分析中的完整流程,从差异基因到motif富集分析,再到结果可视化与生物学解读。通过实战代码演示,帮助研究者掌握这一强大的R包应用,揭示基因表达背后的调控机制,特别适用于基因组学和生物信息学研究。

weixin_29214199的博客 228

android wear app开发教程,Android Wear入门开发之BoxInsetLayout

前面地基基本构建完成,接下来肯定要开始布局咯,所以咱今天要介绍的就是xml布局需要用到的控件BoxInsetLayout。在phone开发的时候,常用组件一般都是RelativeLayout,LineaLayout,FrameLayout等作为父控件,这些控件直接在手表中由于边缘的问题导致布局并不是你想要的那样。例如我在布局中放入三个控件:我在布局中放置了三个控件,但是很奇葩 运行的结果居然是这样...

weixin_42509105的博客 649

S32的进阶之路->3,S32DS新建/删除/导入工程

右击工程名,点击Delect进行工程删除。选中Delect project contents on disk则会彻底删除工程,不选中Delect project contents on disk工程文件会保存在工作空间中。在Improt Projects中选择工程所在文件夹,选中所需要导入的工程,勾选Copy projects into workspace。选中目标示例工程,点击Finish,完成创建工程。导入已有工程,右击右击Project Explorer空白处,选择Import。

LC_8575的博客 2224

安卓穿戴项目(一)

原文:zh.annas-archive.org/md5/C54AD11200D923EEEED7A76F711AA69C 译者:飞龙 协议:CC BY-NC-SA 4.0 前言 Android Wear 2.0 是针对可穿戴智能设备的一个强大平台。从 Wear 发布之日起,Wear 2.0 使可穿戴设备市场的新设备激活率接近 72%。谷歌正在与多个标志性品牌合作,为智能手表带来最佳用户体验。市场上新设备的穿戴硬件不断改进,展示了穿戴设备所具有的潜力。谷歌通过材料设计、独立应用程序、表盘创新等,引入了一种

龙哥盟 864

储能BMS三级架构解析:从模组到堆的管理与控制

本文深入解析了储能电池管理系统(BMS)的核心三级架构,即电池模组管理层(BMU)、电池簇管理层(BCMU)和电池堆管理层(BAMS)。文章详细阐述了各级的职能分工与协同机制,从底层数据采集、均衡管理,到中层信息汇总与安全控制,再到顶层的系统总控与对外通信,揭示了该架构如何实现大规模储能电池的精细化、安全与高效管理。

ik678901234的博客 471

Mamba vs YOLO:目标检测选型指南(附实际项目对比)

本文深入对比了Mamba和YOLO在目标检测领域的性能差异与应用场景。通过实际项目数据,分析了两者在城市交通监控、工业质检等场景下的表现,提供了详细的选型指南和部署优化建议,帮助开发者根据实时性、精度等需求选择最适合的解决方案。

weixin_29062255的博客 368

Wear OS手表应用开发教程之-禁止全屏滑动返回Activity

Wear OS手表应用开发教程之-禁止全屏滑动返回Activity本文标签前言:效果展示使用方法结语最后我还有一句话要说你看不见你自己,你所看见的只是你的影子。Wear OS手表应用开发系列教程 本文标签 Android Studio Wear OS WearableActivity 手表禁止返回 前言: 正如Android一样,Wear OS也是谷歌创建的智能操作系统,属于Android的一个分支。假设你有过Android Application开发经验,那给Wear OS 做应用适配应该

滨江昔岸的博客 4077

STM32cube HAL库两条命令实现i2c通信---Nucleo L476RG用I2C实现tmp117模块温度读取并串口打印

Getting Started with STM32 - I2C Example

m0_54706625的博客 1831

Android可穿戴设备世界之旅

因此,无论是开发还是对代码结构有扎实的了解,您都需要对 Android 应用程序开发方面有一定的了解,还需要具备 JAVA 方面的知识。名为“”的文件定义方形耐磨屏幕的布局,而“”定义圆形耐磨屏幕的布局。首先,我们将集中精力制作一个“Hello Wear”应用程序,该应用程序将演示制作基本磨损应用程序并将应用程序运行到磨损模拟器中的步骤。当我们制作另一个针对方形屏幕的模拟器并运行我们之前所做的相同项目时,输出看起来相似,但文本值不是,因为我们没有更改文件中方形屏幕的 textview 字符串值。

double222222的博客 5776

数据挖掘实战-基于情感分析+网络语义分析对泾阳茯茶用户评论进行文本分析

本实验数据集来源于京东商城,使用Python爬虫获取泾阳茯茶商品的用户评论,共计3416条数据,字段有用户ID、用户昵称、IP属地、评论时间、评分、评论内容,共计6个字段信息。'''作者:艾派森csdn主页:https://blog.youkuaiyun.com/m0_64336780时间:2024/5/28'''# 导包import csv# 获取评论q=0.01',q=0.9,en;b_avif=1;b_dw=1412;b_dh=650;areaId=27;

m0_64336780的博客 1万+

SAP_SD模块-销售批次策略应用记录

SAP_SD模块-销售批次策略完整案例

风沙的博客 2610

Wear OS手表应用开发教程之-创建环形滚动列表-WearableRecyclerView

Wear OS手表应用开发教程之-适配圆形列表-WearableRecyclerView本文标签前言:效果展示使用方法结语最后我还有一句话要说世界上最遥远的距离,不是生与死的距离,不是天各一方,而是,我就站在你的面前,你却不知道我爱你。 Wear OS手表应用开发系列教程 本文标签 Android Studio Wear OS WearableRecyclerView 环形滚动列表 前言: 正如Android一样,Wear OS也是谷歌创建的智能操作系统,属于Android的一个分支。假设你

滨江昔岸的博客 3886

数学之美:欣赏超越数e

文章目录一、e为何物?二、利息与e的关系1、利息问题2、计算利息3、欣赏螺旋线(1)螺旋线概述(2)绘制螺旋线三、e和π 一、e为何物? e是一个无限不循环小数,其值约等于2.718281828…,它是一个超越数,有时也称为欧拉数(Euler’s Number)。 以e为底的对数称为自然对数(Natural Logarithm),数学中使用自然这个词的还有自然数(Natural Number)。 这里的“自然”并不是现代人所习惯的“大自然”,而是有点儿“天然存在,非人为”的意思。 二、利息与e的关系

howard2005的专栏 1717

Wear OS基础介绍及基本创建Wear OS应用的方法

文章目录前言一、Wear OS是什么?二、准备阶段1. 你需要的2. Wear OS与Android相比如何?3. 专用于 Wear OS 的软件包三、开发1. 在 Android Studio 上创建 Wear OS 项目2.1 创建用户界面布局2.2 设置清单3. 最常见的 Wear OS UI 组件4. 使用"BoxInsetLayout"5. 使用"SwipeDismissFrameLayout"6. 导航6.1 使用导航抽屉四、结束 前言 2021年作者开始学习Android开发,一直以来对于

fjnu_se的博客 4916

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

聊聊 Android Wear OS:从系统功能到 Compose 开发的那些事​

摘要: Wear OS 作为主流智能手表系统,经历了从 Android Wear 到 Wear OS 5.1 的迭代,兼容性、健康监测和个性化功能逐步完善。其优势在于交互便捷(如 Tiles 快速访问)、专业健康追踪(整合 Fitbit)、高自由度表盘定制及优化的续航表现。相比 watchOS 和鸿蒙 OS,Wear OS 以跨品牌兼容性和丰富应用生态见长。开发时需聚焦核心功能、适配小屏交互、优化功耗,并遵循 Material Design 规范。与手机应用开发相比,Wear OS 更强调简洁交互和独立运行

移动端开发干货分享 1913

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

从0到1开发Wear OS应用:基于wear-os-samples的完整项目实战

Wear OS应用开发入门不再困难!本文将带你通过wear-os-samples项目,从零开始掌握Wear OS应用开发的核心技能。这个官方示例仓库包含多个精心设计的项目,涵盖了从基础UI到高级功能的全部实践要点,是新手开发者的理想学习资源。 ## 📋 为什么选择wear-os-samples? wear-os-samples是Google官方提供的Wear OS开发示例集合,包含8个核心项

gitblog_00943的博客 765

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

douyin-downloader:10 分钟跑通抖音无水印批量下载,附命名与去重规则

douyin-downloader 是一个抖音无水印下载工具。传入用户主页链接即可批量拉取无水印作品,下面讲清从装环境到只存新作品的全套设置。 ## 跑通一次:装依赖并拿到抖音 Cookie 环境要 Python 3.9 以上,Windows、macOS、Linux 三个平台都行。 拉取代码、装依赖、复制配置。 ```bash git clone https://gitcode.com/G

gitblog_00107的博客 637

10分钟上手Horologist:Wear OS开发者的终极工具包

Horologist是专为Wear OS开发者打造的功能丰富的工具库集合,旨在提供开发中常用但系统尚未原生支持的功能模块。无论你是刚接触智能手表开发的新手,还是寻求高效解决方案的资深开发者,Horologist都能帮助你快速构建专业级Wear OS应用。 ## 📦 核心功能模块概览 Horologist涵盖了Wear OS开发的多个关键领域,每个模块都针对智能手表的特殊交互场景进行了优化:

gitblog_00126的博客 874

使用 Compose 构建 Wear OS 应用

适用于 Wear OS 的 Compose 已推出了 开发者预览版,使用 Compose 构建 Wear OS 应用,不仅可以轻松遵循 Material You 指南,同时可以将 Compose 的优点发挥出来。开箱即用,帮助开发者使用更少的代码快速构建出更精美的 Wear OS 应用。本文将通过 Wear Compose 主要的可组合项 (Composable) 来帮助您更好地了解如何使用 Compose 来进行构建。 如果您更喜欢通过视频了解此内容,请 点击此处 查看。 △ 主应用界面和通知界面 移.

Android开发者 897

Horologist Media Toolkit详解:构建专业Wear OS媒体应用的完整指南

Horologist Media Toolkit是一套专为Wear OS开发者设计的强大库集合,旨在提供开发媒体应用时常用但官方尚未提供的关键功能。无论是构建音乐播放器、播客应用还是音频流媒体服务,这个工具包都能帮助开发者快速实现专业级的用户界面和核心功能,让Wear OS设备上的媒体体验更上一层楼。 ## 📚 核心功能模块概览 Horologist Media Toolkit包含多个紧密协

gitblog_01050的博客 777

谷歌将Gemini AI扩展至Android Auto、Wear OS、谷歌电视及耳机设备

谷歌Gemini是一款AI聊天机器人,提供直接访问谷歌AI的功能,用于写作、规划和学习等任务。它被评为3.2分,提供AI驱动的助手、无广告体验和拼写检查等功能。主要替代品包括ChatGPT、HuggingChat和Mistral Le Chat。谷歌正在将其Gemini人工智能平台引入更多设备,包括Android Auto、Wear OS、谷歌电视以及某些索尼和三星耳机。

心雨楼 1273

从0到1:使用Horologist开发你的第一个Wear OS应用

Horologist是一个为Wear OS开发者提供补充功能的开源库集合,旨在解决开发中常见但官方尚未提供的需求。本文将带你快速入门,使用Horologist构建你的第一个Wear OS媒体应用,无需复杂代码即可实现专业级功能。 ## 📋 准备工作 ### 环境要求 - Android Studio Hedgehog或更高版本 - Wear OS模拟器或实体设备(API 26+) - Kot

gitblog_01192的博客 648

Horologist Tiles开发教程:创建高效Wear OS快捷功能卡片

Horologist是一个为Wear OS开发者提供补充功能的库集合,其中Tiles模块能够帮助开发者快速构建高效的Wear OS快捷功能卡片。本教程将带你了解如何利用Horologist Tiles库创建实用的Wear OS快捷功能卡片,让你的应用在智能手表上提供更便捷的用户体验。 ## 什么是Horologist Tiles? Horologist Tiles是Horologist项目中的

gitblog_00261的博客 415

LÖVE:用 Lua 十几行代码跑出 2D 游戏的轻量框架

想做个横版跳跃小游戏,或者一个"弹球撞墙壁"的演示,但你不想为此拖进一个体积庞大、启动要等一分钟的完整引擎,也不想先学三天编辑器再写第一行逻辑。你需要的是一个足够薄的 2D 游戏框架:界面、渲染、声音、输入全帮你兜底,而你只用一门脚本语言写规则。LÖVE 就是干这件事的——你的游戏逻辑全部是 Lua,框架把剩下的脏活干了。 ## 项目速写 LÖVE(读作 love,全称 Live Of Vir

gitblog_00550的博客 997

wear OS系统详解

其 Galaxy Watch 系列(如 Watch 6 Classic)凭借顶级的 Super AMOLED 屏幕、标志性的旋转物理表圈(部分型号)、强大的性能和成熟的 One UI Watch 界面,成为了 Wear OS 阵营的标杆。展望未来,随着芯片能效的进一步提升和软件算法的持续优化,Wear OS 有望在解决续航痛点的同时,带来更多基于 AI 的主动式、预测性智能体验,成为更加无感且不可或缺的个人数字助理。◦ 与三星的联姻: 这是 Wear OS 历史上最重要的里程碑。

bulita great world 1679

如何使用Horologist Composables:打造精美Wear OS时间选择界面

Horologist是一个为Wear OS开发者提供补充功能的开源库集合,专注于解决开发中常见但系统尚未提供的需求。其中Horologist Composables模块提供了丰富的UI组件,帮助开发者快速构建符合Wear OS设计规范的应用界面,时间选择组件就是其中的亮点功能。 ## 为什么选择Horologist Composables时间选择器? Wear OS设备由于屏幕尺寸限制,传统的

gitblog_00039的博客 833
上一篇: 小计-保存网络图片
下一篇: android-图书购买APP
雪酒呀
博客等级 码龄6年 3609粉丝 122原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值