当前位置: 首页 > news >正文

安卓开发---耳机的按键设置的UI实例

效果图

主页面

弹窗的点击事件

选择完成后更新主页UI

项目的系统架构设计图

一般的列表适配器:主页面,主页面UI,列表子项数据类,列表适配器,子项UI

Caches:存储持久化数据

MyApplication:初始化数据

分层架构

  • 应用层​​:MainActivity处理UI交互

  • ​业务逻辑层​​:Caches管理配置数据

  • ​数据持久层​​:SharedPreferences本地存储

  • ​视图层​​:RecyclerView+ 自定义对话框

数据流转的例子

// 以用户设置左耳双击的功能值为例:
①MainActivity检测到点击事件
②通过Caches读取当前配置:"LEFT_btn_action_2"
③BottomSheetDialog显示可选功能值的列表
④用户选择"下一首"触发:
   - Caches.saveButtonAction(2, "下一首", true)
   - updateButtonDisplay(2, "下一首")
⑤新配置立即持久化到SharedPreferences

分析关键代码

1.Caches中的存储方法,保证重新进入页面的时候能够保持之前的选项

//存入功能值
//示例:"LEFT_btn_action_1"  : 左耳第1个按钮的功能值
public void saveButtonAction(int buttonIndex, String actionName, boolean isLeft) {String key = (isLeft ? "LEFT_" : "RIGHT_") + BUTTON_ACTIONS_PREFIX + buttonIndex;sharedPreferences.edit().putString(key, actionName).apply();
}
//获取功能值,默认为无作用
public String getButtonAction(int buttonIndex, boolean isLeft) {String key = (isLeft ? "LEFT_" : "RIGHT_") + BUTTON_ACTIONS_PREFIX + buttonIndex;return sharedPreferences.getString(key, DEFAULT_ACTION);
}

SharedPreferences的基本方法

写入

// 获取编辑器
SharedPreferences.Editor editor = sp.edit();// 存储不同类型数据
editor.putString("username", "Alice");
editor.putInt("age", 25);
editor.putBoolean("isPremium", true);
editor.putFloat("score", 4.5f);
editor.putLong("timestamp", System.currentTimeMillis());// 提交更改(同步/异步)
editor.apply(); // 异步(无返回值)
editor.commit(); // 同步(返回boolean表示成功)

读取

//第一个参数为key,第二个参数为默认值
String username = sp.getString("username", "default");
int age = sp.getInt("age", 0);
boolean isPremium = sp.getBoolean("isPremium", false);
float score = sp.getFloat("score", 0.0f);
long timestamp = sp.getLong("timestamp", -1L);

删除

editor.remove("username"); // 删除指定键
editor.clear();            // 清空所有数据
editor.apply();

2.用定义的整数来区分按钮

private int oneclick_1 = 1, doubleclick_2 = 2, threeclick_3 = 3, longpress_4 = 4; //用于区分按钮

3.简化onCreate方法,把获取视图和点击事件写初始化方法分出去

 protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//初始化initView();initClick();initListDate();}

4.列表的列表项右边有默认的隐藏图片,当用户点击列表项的时候,就显示出来,并且用户下次打开弹窗,这个隐藏图片依然显示

在Activity里面//初始化选中项,遍历列表找到与缓存匹配的项for (int i = 0; i < keyList.size(); i++) {if (keyList.get(i).getName().equals(currentAction)) {adapter.setSelectedPosition(i);//把选中的位置传给适配器break;}}在Adapter里面
// 选中状态管理(自动取消旧项选中状态,严格保证唯一选中项)public void setSelectedPosition(int position) {if (selectedPosition != position) {//检查新旧位置是否不同int oldPosition = selectedPosition;//保存旧位置selectedPosition = position;//更新当前选中位置if (oldPosition != -1) {//如果旧位置有效notifyItemChanged(oldPosition);//就刷新旧位置}notifyItemChanged(selectedPosition);//刷新新项UI}}

5.在适配器中使用监视器

详情参考以下链接:

安卓开发---在适配器中使用监听器-CSDN博客

实例代码

新建类MyApplication,然后在AndroidManifest.xml里面的application里面加上android:name=".MyApplication",目的是:告诉系统MyApplication是应用的全局入口点,继承自 android.app.Application它会在应用启动时 ​​最先初始化​​(早于任何 Activity/Service),像在这个项目里面,可以初始化Caches。

MyApplication:初始化

package com.example.myapplication;import android.app.Application;/*执行初始化操作*/
public class MyApplication extends Application {@Overridepublic void onCreate() {super.onCreate();Caches.init(this);}
}

String.xml:存储文本

<resources><string name="app_name">My Application</string><string name="disconnected">未连接</string><!-- TODO: Remove or change this placeholder text --><string name="hello_blank_fragment">Hello blank fragment</string><string name="one_click">单击</string><string name="double_click">双击</string><string name="three_click">三连击</string><string name="long_press">长按</string><string name="save">保存</string><string name="play_stop">播放/暂停</string><string name="no_effect">无作用</string><string name="audio_assistant">语音助手</string><string name="previous">上一首</string><string name="next">下一首</string><string name="volume_add">音量加</string><string name="volume_sub">音量减</string><string name="anc_change">ANC切换</string></resources>

dialog_key_setting_select.xml:弹窗的UI

<?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="vertical"android:background="@color/white"android:padding="16dp"><TextViewandroid:id="@+id/tv_title"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="请选择"android:textSize="16sp"android:textStyle="bold"android:gravity="center"android:padding="8dp"android:textColor="@color/black"/><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/rv_actions"android:layout_width="match_parent"android:layout_height="wrap_content"/></LinearLayout>

key_setting_item.xml:子项UI

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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="48dp"android:padding="12dp"><TextViewandroid:id="@+id/tv_action"android:layout_width="0dp"android:layout_height="wrap_content"android:text="选项"android:textColor="@color/black"android:textSize="15sp"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toStartOf="@id/iv_selected"/><ImageViewandroid:id="@+id/iv_selected"android:layout_width="20dp"android:layout_height="20dp"android:src="@mipmap/select_icon"android:visibility="gone"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent"/></androidx.constraintlayout.widget.ConstraintLayout>

activity_main.xml:主页面UI

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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/main"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".MainActivity"android:layout_marginTop="30dp"><TextViewandroid:id="@+id/tv_earLR"android:layout_width="161dp"android:layout_height="40dp"tools:ignore="MissingConstraints"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"android:background="@color/gray"android:layout_marginTop="222dp"/><TextViewandroid:id="@+id/tv_left_earphone"android:layout_width="80.5dp"android:layout_height="40dp"tools:ignore="MissingConstraints"app:layout_constraintStart_toStartOf="@id/tv_earLR"app:layout_constraintTop_toTopOf="@id/tv_earLR"android:text="左耳"android:textColor="@color/white"android:gravity="center"android:background="@color/blue"/><TextViewandroid:id="@+id/tv_right_earphone"android:layout_width="80.5dp"android:layout_height="40dp"tools:ignore="MissingConstraints"app:layout_constraintEnd_toEndOf="@id/tv_earLR"app:layout_constraintTop_toTopOf="@id/tv_earLR"android:text="右耳"android:gravity="center"/><androidx.constraintlayout.widget.ConstraintLayoutandroid:id="@+id/cl_click"android:layout_width="match_parent"android:layout_height="184dp"android:background="@color/white"app:layout_constraintTop_toTopOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintEnd_toEndOf="parent"android:layout_marginTop="342dp"android:layout_marginStart="25dp"android:layout_marginEnd="25dp"><ImageViewandroid:id="@+id/iv_one_click"android:layout_width="20dp"android:layout_height="20dp"android:src="@mipmap/ic_launcher"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent"android:layout_marginTop="19.5dp"android:layout_marginBottom="158.5dp"android:layout_marginStart="23dp"/><TextViewandroid:id="@+id/tv_one_click"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/one_click"android:textColor="@color/black"android:textSize="15sp"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent"android:layout_marginTop="15dp"android:layout_marginStart="49dp"android:layout_marginBottom="154dp"/><TextViewandroid:id="@+id/tv_one_click_display"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/play_stop"android:textColor="@color/word_gray"android:textSize="15sp"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"android:layout_marginTop="16dp"android:layout_marginBottom="155.5dp"android:layout_marginEnd="35dp"/><ImageViewandroid:id="@+id/iv_one_forward"android:layout_width="100dp"android:layout_height="45dp"tools:ignore="MissingConstraints"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent"android:layout_marginTop="16dp"android:layout_marginStart="302dp"android:layout_marginBottom="154dp"android:layout_marginEnd="14.5dp"/><ImageViewandroid:layout_width="20dp"android:layout_height="25dp"android:src="@drawable/baseline_arrow_forward_ios_24"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent"android:layout_marginTop="16dp"android:layout_marginStart="302dp"android:layout_marginBottom="154dp"android:layout_marginEnd="14.5dp"/><!-- 分割线1 --><Viewandroid:id="@+id/divider1"android:layout_width="match_parent"android:layout_height="0.5dp"android:background="@color/word_gray"app:layout_constraintTop_toTopOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintEnd_toEndOf="parent"android:layout_marginTop="45dp"android:layout_marginBottom="138.5dp"/><ImageViewandroid:id="@+id/iv_double_click"android:layout_width="20dp"android:layout_height="20dp"android:src="@mipmap/ic_launcher"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent"android:layout_marginTop="65.5dp"android:layout_marginBottom="112.5dp"android:layout_marginStart="23dp"/><TextViewandroid:id="@+id/tv_double_click"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/double_click"android:textColor="@color/black"android:textSize="15sp"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent"android:layout_marginTop="61.5dp"android:layout_marginStart="48.5dp"android:layout_marginBottom="108dp"/><TextViewandroid:id="@+id/tv_double_click_display"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/volume_add"android:textColor="@color/word_gray"android:textSize="15sp"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"android:layout_marginTop="62.5dp"android:layout_marginBottom="109.5dp"android:layout_marginEnd="35dp"/><ImageViewandroid:id="@+id/iv_double_forward"android:layout_width="100dp"android:layout_height="45dp"tools:ignore="MissingConstraints"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent"android:layout_marginTop="60.5dp"android:layout_marginBottom="108dp"android:layout_marginEnd="14.5dp"/><ImageViewandroid:layout_width="20dp"android:layout_height="25dp"android:src="@drawable/baseline_arrow_forward_ios_24"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent"android:layout_marginTop="60.5dp"android:layout_marginBottom="108dp"android:layout_marginEnd="14.5dp"/><!-- 分割线2 --><Viewandroid:id="@+id/divider2"android:layout_width="match_parent"android:layout_height="0.5dp"android:background="@color/word_gray"app:layout_constraintTop_toTopOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintEnd_toEndOf="parent"android:layout_marginTop="91dp"android:layout_marginBottom="92.5dp"/><ImageViewandroid:id="@+id/iv_three_click"android:layout_width="20dp"android:layout_height="20dp"android:src="@mipmap/ic_launcher"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent"android:layout_marginTop="111.5dp"android:layout_marginBottom="66.5dp"android:layout_marginStart="23dp"/><TextViewandroid:id="@+id/tv_three_click"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/three_click"android:textColor="@color/black"android:textSize="15sp"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent"android:layout_marginTop="107dp"android:layout_marginStart="48.5dp"android:layout_marginBottom="62dp"/><TextViewandroid:id="@+id/tv_three_click_display"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/previous"android:textColor="@color/word_gray"android:textSize="15sp"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"android:layout_marginTop="107.5dp"android:layout_marginBottom="64.5dp"android:layout_marginEnd="35dp"/><ImageViewandroid:id="@+id/iv_three_forward"android:layout_width="100dp"android:layout_height="45dp"tools:ignore="MissingConstraints"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent"android:layout_marginTop="106.5dp"android:layout_marginBottom="62dp"android:layout_marginEnd="14.5dp"/><ImageViewandroid:layout_width="20dp"android:layout_height="25dp"android:src="@drawable/baseline_arrow_forward_ios_24"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent"android:layout_marginTop="106.5dp"android:layout_marginBottom="62dp"android:layout_marginEnd="14.5dp"/><!-- 分割线3 --><Viewandroid:id="@+id/divider3"android:layout_width="match_parent"android:layout_height="0.5dp"android:background="@color/word_gray"app:layout_constraintTop_toTopOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintEnd_toEndOf="parent"android:layout_marginTop="137dp"android:layout_marginBottom="46.5dp"/><ImageViewandroid:id="@+id/iv_long_press"android:layout_width="20dp"android:layout_height="20dp"android:src="@mipmap/ic_launcher"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent"android:layout_marginTop="158dp"android:layout_marginBottom="21dp"android:layout_marginStart="23dp"/><TextViewandroid:id="@+id/tv_long_press"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/long_press"android:textColor="@color/black"android:textSize="15sp"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent"android:layout_marginTop="153dp"android:layout_marginStart="49dp"android:layout_marginBottom="16dp"/><TextViewandroid:id="@+id/tv_long_press_display"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/audio_assistant"android:textColor="@color/word_gray"android:textSize="15sp"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"android:layout_marginTop="155dp"android:layout_marginBottom="17dp"android:layout_marginEnd="35dp"/><ImageViewandroid:layout_width="20dp"android:layout_height="25dp"android:src="@drawable/baseline_arrow_forward_ios_24"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent"android:layout_marginTop="152.5dp"android:layout_marginBottom="16dp"android:layout_marginEnd="14.5dp"/><ImageViewandroid:id="@+id/iv_long_forward"android:layout_width="100dp"android:layout_height="45dp"tools:ignore="MissingConstraints"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toBottomOf="parent"android:layout_marginTop="152.5dp"android:layout_marginBottom="16dp"android:layout_marginEnd="14.5dp"/></androidx.constraintlayout.widget.ConstraintLayout></androidx.constraintlayout.widget.ConstraintLayout>

Caches:存储持久化数据

package com.example.myapplication;import android.content.Context;
import android.content.SharedPreferences;//基于 SharedPreferences实现的轻量级缓存工具类
public class Caches {// 按键常量定义private static final String BUTTON_TITLES_PREFIX = "btn_title_";private static final String BUTTON_ACTIONS_PREFIX = "btn_action_";private static final String DEFAULT_ACTION = "无作用";SharedPreferences sharedPreferences;private SharedPreferences.Editor editor;//单例模式private static volatile Caches instance;// 初始化方法(必须首先调用)public static void init(Context context) {if (instance == null) {instance = new Caches(context.getApplicationContext());}}// 获取实例(确保已初始化)public static Caches getInstance() {if (instance == null) {throw new IllegalStateException("Caches must be initialized first!");}return instance;}//构造函数private Caches(Context context) {sharedPreferences = context.getSharedPreferences("app_cache", Context.MODE_PRIVATE);editor = sharedPreferences.edit();}//=== 按钮配置方法 ===////保存按钮对应的显示文字,buttonIndex表示按钮编号,title是标题,isLeft判断左右耳//示例:"LEFT_btn_title_1"  // 左耳第1个按钮的标题public void saveButtonTitle(int buttonIndex, String title, boolean isLeft) {String key = (isLeft ? "LEFT_" : "RIGHT_") + BUTTON_TITLES_PREFIX + buttonIndex;sharedPreferences.edit().putString(key, title).apply();}//读取标题(无缓存时返回null)public String getButtonTitle(int buttonIndex, boolean isLeft) {String key = (isLeft ? "LEFT_" : "RIGHT_") + BUTTON_TITLES_PREFIX + buttonIndex;return sharedPreferences.getString(key, null);}//存入功能值//示例:"LEFT_btn_action_1"  // 左耳第1个按钮的功能值public void saveButtonAction(int buttonIndex, String actionName, boolean isLeft) {String key = (isLeft ? "LEFT_" : "RIGHT_") + BUTTON_ACTIONS_PREFIX + buttonIndex;sharedPreferences.edit().putString(key, actionName).apply();}//获取功能值,默认为无作用public String getButtonAction(int buttonIndex, boolean isLeft) {String key = (isLeft ? "LEFT_" : "RIGHT_") + BUTTON_ACTIONS_PREFIX + buttonIndex;return sharedPreferences.getString(key, DEFAULT_ACTION);}}

KeySetting:列表子项数据类

package com.example.myapplication;public class KeySetting {private String name;public KeySetting(String name) {this.name = name;}public String getName() {return name;}}

KeySettingAdapter:列表适配器

package com.example.myapplication;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.recyclerview.widget.RecyclerView;import java.util.List;public class KeySettingAdapter extends RecyclerView.Adapter<KeySettingAdapter.ViewHolder> {//定义数据成员(KeySetting)类型,用于接收Activitiy调用适配器是传递数据,实现数据共享private List<KeySetting> keyListInAdapter;//数据源:选项列表private int selectedPosition = -1;//当前选中项的位置,-1表示未选中//构造函数public KeySettingAdapter(List<KeySetting> keyListInAdapter) {this.keyListInAdapter = keyListInAdapter;}// 1.【定义监听接口】添加点击监听器接口public interface OnItemClickListener {void onItemClick(int position, KeySetting item);}//2.【设置监听器】将外部传入的监听器对象保存到适配器成员变量中private OnItemClickListener onItemClickListener;public void setOnItemClickListener(OnItemClickListener listener) {this.onItemClickListener = listener;}//返回列表项总数@Overridepublic int getItemCount() {return keyListInAdapter.size();}//布局:通过inflate方法将列表项item布局编译为view对象,返回以这个对象为参数的ViewHolder对象(就是创建viewHolder)@NonNull@Overridepublic ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.key_setting_item, parent, false);return new ViewHolder(view);}//将数据渲染到列表项的ViewHolder的view控件中(就是绑定数据)@Overridepublic void onBindViewHolder(@NonNull ViewHolder holder, int position) {//给第position条目 绑定数据(从0开始计数) 对应的数据是keyListInAdapter的position个元素KeySetting item = keyListInAdapter.get(position);holder.tvAction.setText(item.getName());//控制选中图标显示还是隐藏,选中就显示,未选择就隐藏holder.ivSelected.setVisibility(position == selectedPosition ? View.VISIBLE : View.GONE);//设置点击事件//当用户点击某个列表项时,触发回调通知外部//【触发监听】当列表项的任意区域被点击时holder.itemView.setOnClickListener(v -> {//为整个列表项设置点击监听器dint adapterPosition = holder.getAdapterPosition();//获取当前点击项在Adapter中的位置//检查位置是否有效:adapterPosition != RecyclerView.NO_POSITION//检查监听器是否已经设置:onItemClickListener != nullif (adapterPosition != RecyclerView.NO_POSITION && onItemClickListener != null) {//触发回调,传递两个关键数据,点击的位置索引,点击项的数据对象onItemClickListener.onItemClick(adapterPosition, keyListInAdapter.get(adapterPosition));}});}// 选中状态管理(自动取消旧项选中状态,严格保证唯一选中项)public void setSelectedPosition(int position) {if (selectedPosition != position) {//检查新旧位置是否不同int oldPosition = selectedPosition;//保存旧位置selectedPosition = position;//更新当前选中位置if (oldPosition != -1) {//如果旧位置有效notifyItemChanged(oldPosition);//就刷新旧位置}notifyItemChanged(selectedPosition);//刷新新项UI}}// 获取当前选中项public int getSelectedPosition() {return selectedPosition;}//新建viewHolderstatic class ViewHolder extends RecyclerView.ViewHolder {TextView tvAction;ImageView ivSelected;public ViewHolder(@NonNull View itemView) {super(itemView);tvAction = itemView.findViewById(R.id.tv_action);ivSelected = itemView.findViewById(R.id.iv_selected);}}
}

MainActivity.java:主页面

package com.example.myapplication;import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;import com.google.android.material.bottomsheet.BottomSheetDialog;import java.util.ArrayList;
import java.util.List;public class MainActivity extends AppCompatActivity {private static final String TAG = "MainActivity";//UIprivate TextView leftEarphone, rightEarphone; //左耳,右耳private ImageView oneClickForward, doubleClickForward, threeClickForward, longPressForward; //单击,双击,三击,长按private TextView oneClickWoldDispaly, doubleClickWoldDispaly, threeClickWoldDispaly, longPressWoldDispaly; //显示的功能值private int oneclick_1 = 1, doubleclick_2 = 2, threeclick_3 = 3, longpress_4 = 4; //用于区分按钮private boolean isLeftSelected = true; // 当前选中的耳朵,默认左耳(true 左耳,false 右耳)private BottomSheetDialog dialog; // 当前显示的对话框List<KeySetting> keyList = new ArrayList<>();//数据列表@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//初始化initView();initClick();initListDate();// 初始化加载配置loadButtonConfigs();selectEarUI(); // 触发首次UI更新}@Overrideprotected void onPause() {super.onPause();dismissCurrentDialog();}// 初始化列表数据private void initListDate() {keyList.add(new KeySetting("无作用"));keyList.add(new KeySetting("语音助手"));keyList.add(new KeySetting("上一首"));keyList.add(new KeySetting("下一首"));keyList.add(new KeySetting("音量加"));keyList.add(new KeySetting("音量减"));keyList.add(new KeySetting("播放/暂停"));keyList.add(new KeySetting("ANC切换"));}//1.获取视图private void initView() {leftEarphone = findViewById(R.id.tv_left_earphone);rightEarphone = findViewById(R.id.tv_right_earphone);oneClickForward = findViewById(R.id.iv_one_forward);doubleClickForward = findViewById(R.id.iv_double_forward);threeClickForward = findViewById(R.id.iv_three_forward);longPressForward = findViewById(R.id.iv_long_forward);oneClickWoldDispaly = findViewById(R.id.tv_one_click_display);doubleClickWoldDispaly = findViewById(R.id.tv_double_click_display);threeClickWoldDispaly = findViewById(R.id.tv_three_click_display);longPressWoldDispaly = findViewById(R.id.tv_long_press_display);}//2.点击事件private void initClick() {// 按钮点击事件oneClickForward.setOnClickListener(v -> showSelectDialog(oneclick_1));doubleClickForward.setOnClickListener(v -> showSelectDialog(doubleclick_2));threeClickForward.setOnClickListener(v -> showSelectDialog(threeclick_3));longPressForward.setOnClickListener(v -> showSelectDialog(longpress_4));// 左耳点击事件leftEarphone.setOnClickListener(view -> {isLeftSelected = true;selectEarUI();//更新UI});// 右耳点击事件rightEarphone.setOnClickListener(view -> {isLeftSelected = false;selectEarUI();//更新UI});}// 3.初始化 UI, 从Caches读取4个按钮的功能值,默认显示左耳private void loadButtonConfigs() {// 加载当前选中耳朵的配置updateButtonDisplays(isLeftSelected);}//读存储,更新用来显示的功能值private void updateButtonDisplays(boolean isLeft) {oneClickWoldDispaly.setText(Caches.getInstance().getButtonAction(oneclick_1, isLeft));doubleClickWoldDispaly.setText(Caches.getInstance().getButtonAction(doubleclick_2, isLeft));threeClickWoldDispaly.setText(Caches.getInstance().getButtonAction(threeclick_3, isLeft));longPressWoldDispaly.setText(Caches.getInstance().getButtonAction(longpress_4, isLeft));}// 4.修改按键的UIprivate void selectEarUI() {Log.d(TAG, "选中耳机: " + (isLeftSelected ? "左耳" : "右耳"));leftEarphone.setBackgroundColor(ContextCompat.getColor(this,isLeftSelected ? R.color.blue : R.color.gray));leftEarphone.setTextColor(ContextCompat.getColor(this,isLeftSelected ? R.color.white : R.color.black));rightEarphone.setBackgroundColor(ContextCompat.getColor(this,!isLeftSelected ? R.color.blue : R.color.gray));rightEarphone.setTextColor(ContextCompat.getColor(this,!isLeftSelected ? R.color.white : R.color.black));// 切换按钮时,重新从caches里面更新按钮的功能值updateButtonDisplays(isLeftSelected);}// 5.弹窗展示private void showSelectDialog(int buttonIndex) {// 先销毁已有对话框,确保同一时间只存在一个对话框实例dismissCurrentDialog();//创建新对话框dialog = new BottomSheetDialog(this);//加载对话框布局View view = LayoutInflater.from(this).inflate(R.layout.dialog_key_setting_select, null);dialog.setContentView(view);//获取子视图TextView tvTitle = view.findViewById(R.id.tv_title);//子项的标题RecyclerView rv = view.findViewById(R.id.rv_actions);//子项的列表// 同步标题文字:从Caches读取当前按键的标题String savedTitle = Caches.getInstance().getButtonTitle(buttonIndex, isLeftSelected);//同步获取当前对话框设置的功能值String currentAction = Caches.getInstance().getButtonAction(buttonIndex, isLeftSelected);tvTitle.setText(savedTitle != null ? savedTitle : "请选择");//配置适配器rv.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));//设置分割线rv.setLayoutManager(new LinearLayoutManager(this));// 设置适配器,将列表数据绑定到RecyclerViewKeySettingAdapter adapter = new KeySettingAdapter(keyList);rv.setAdapter(adapter);//初始化选中项,遍历列表找到与缓存匹配的项for (int i = 0; i < keyList.size(); i++) {if (keyList.get(i).getName().equals(currentAction)) {adapter.setSelectedPosition(i);//把选中的位置传给适配器break;}}//设置列表项点击监听器//【外部使用监听器】实现接口adapter.setOnItemClickListener((position, item) -> {// 写入缓存,只写当前耳朵Caches.getInstance().saveButtonTitle(buttonIndex, item.getName(), isLeftSelected);Caches.getInstance().saveButtonAction(buttonIndex, item.getName(), isLeftSelected);// 更新UIupdateButtonDisplay(buttonIndex, item.getName());adapter.setSelectedPosition(position);//用户点击时,更新选中状态tvTitle.setText(item.getName());});dialog.setOnDismissListener(dialog -> {dialog = null; // 清除引用});dialog.show();}//销毁对话框private void dismissCurrentDialog() {if (dialog != null && dialog.isShowing()) {dialog.dismiss();dialog = null;}}// 6.把按钮和标题传进来,就立刻更新按钮的显示,(主页面显示的功能值)private void updateButtonDisplay(int buttonIndex, String newTitle) {switch (buttonIndex) {case 1:oneClickWoldDispaly.setText(newTitle);break;case 2:doubleClickWoldDispaly.setText(newTitle);break;case 3:threeClickWoldDispaly.setText(newTitle);break;case 4:longPressWoldDispaly.setText(newTitle);break;}}
}

http://www.dtcms.com/a/422625.html

相关文章:

  • 苍穹外卖-菜品新增、删除
  • 如何找到到自己研究领域的经典论文?
  • Kubernetes 健康探针详解
  • 出售东西的网站怎么做建设网站运营成本
  • 【Qt开发】输入类控件(三)-> QComboBox
  • 什么是专用对讲机?遨游专用对讲机有什么优势?
  • 港大和字节携手打造WorldWeaver:以统一建模方案整合感知条件,为长视频生成领域带来质量与一致性双重飞跃。
  • 第三方软件测试公司:【Gatling基于Scala的开源高性能负载测试工具】
  • Social-Auto-Upload - 多平台社交媒体视频自动化上传工具
  • 十一、Hadoop 三种部署模式对比表 组件介绍
  • 十、Hadoop 核心目录功能说明表
  • Leetcode+Java+图论+岛屿问题
  • 容器内部DNS解析针对美国服务器微服务的调试指南
  • 生物科技公司网站模板下载织梦教育咨询企业网站模板
  • 镇江网站建设要多少钱开网店3个月来亏了10万
  • 入侵检测系统(IDS)和入侵防御系统(IPS)
  • 【Youtube】油管上有哪些计算机或互联网历史故事频道?
  • 设计模式:单例模式。饿汉式、懒汉式
  • 如何在项目中选择使用HTTP还是WebSocket?
  • 【代码的暴力美学】-- C语言基础编程题_2
  • GPIO 控制和操作-使用命令通过sysfs文件系统控制GPIO
  • MySQL InnoDB存储引擎表的逻辑存储结构及实现原理详细介绍
  • 网站建设实习周记网站推广建设策略
  • RN 升级react-native 版本
  • RabbitMQ 消费异常:库存不足无法释放的定位与解决
  • 邳州做网站pzwode网站开发的相关技术
  • 精读C++20设计模式——结构型设计模式:代理模式
  • C# 循环和条件用法大全(while dowhile for foreach if Switch try)全站最全
  • 设计模式(C++)详解——中介者模式(3)
  • 小程序原创--基于微信开发者工具实现的猜谜游戏程序