最近,我发现许多抖音用户喜欢将小说内容一句一句地发到游戏评论框中。这种行为虽然能让更多人看到这些内容,但手动复制和粘贴却是一个繁琐的过程。为了简化这一操作,我决定开发一个应用,可以一键输入大量文本,并将其根据句号、逗号和分号划分成句子。用户可以通过一个悬浮窗轻松访问上一句、当前句子和下一句,进一步简化操作。
在这个应用的开发过程中,我使用了 Android 的三个重要组件:Fragment、ViewModel 和 View Binding。下面,我将详细介绍这三者的关系以及如何实现具体功能的代码。
1. Fragment
Fragment 是 Android UI 的一部分,可以被看作一个独立的界面模块。在应用中,多个 Fragment 可以在同一个 Activity 中共存,各自管理自己的 UI 和生命周期事件。在我们的应用中,HomeFragment 负责与用户交互,例如输入文本和处理按钮点击事件。
以下是 HomeFragment 的完整代码:
package cn.techfanyi.ui.home;import android.os.Bundle;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;import cn.techfanyi.databinding.FragmentHomeBinding;public class HomeFragment extends Fragment {private FragmentHomeBinding binding;private HomeViewModel homeViewModel;public View onCreateView(@NonNull LayoutInflater inflater,ViewGroup container, Bundle savedInstanceState) {// 创建ViewModelhomeViewModel = new ViewModelProvider(this).get(HomeViewModel.class);// 绑定视图binding = FragmentHomeBinding.inflate(inflater, container, false);View root = binding.getRoot();// 获取输入框和按钮EditText editText = binding.editText; // 假设在XML中有一个EditText用于输入Button recognizeButton = binding.recognizeButton; // 假设在XML中有一个按钮用于识别TextView resultTextView = binding.resultTextView; // 显示结果的TextView// 设置按钮点击事件recognizeButton.setOnClickListener(v -> {String inputText = editText.getText().toString();if (TextUtils.isEmpty(inputText)) {Toast.makeText(getContext(), "请输入文本", Toast.LENGTH_SHORT).show();return;}// 将输入的文本划分为句子String[] sentences = inputText.split("[。;,]");homeViewModel.setSentences(sentences); // 将句子存储到ViewModel中// 更新结果文本resultTextView.setText(TextUtils.join("\n", sentences));});return root;}@Overridepublic void onDestroyView() {super.onDestroyView();binding = null;}
}
2. ViewModel
ViewModel 是 Android 架构组件,用于存储和管理与 UI 相关的数据。其主要作用是持久化数据,使其能够在 Fragment 或 Activity 的生命周期变化(如屏幕旋转)时依然可用。在我们的应用中,HomeViewModel 用于管理文本数据和句子划分的逻辑。
以下是 HomeViewModel 的代码:
package cn.techfanyi.ui.home;import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;public class HomeViewModel extends ViewModel {private final MutableLiveData<String[]> sentences;public HomeViewModel() {sentences = new MutableLiveData<>();}// 设置句子public void setSentences(String[] sentencesArray) {sentences.setValue(sentencesArray);}// 获取句子public LiveData<String[]> getSentences() {return sentences;}
}
3. View Binding
View Binding 是一种更安全和高效的方式来访问 XML 布局中的视图。它会为每个 XML 布局文件生成一个绑定类,可以直接通过绑定类访问布局中的视图,而无需手动调用 findViewById()。
在本应用中,假设我们的布局文件为 fragment_home.xml,以下是示例 XML 布局代码:
<?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:layout_width="match_parent"android:layout_height="match_parent"tools:context=".ui.home.HomeFragment"><EditTextandroid:id="@+id/editText"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="请输入长句子" /><Buttonandroid:id="@+id/recognizeButton"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="识别句子"app:layout_constraintTop_toBottomOf="@id/editText"app:layout_constraintStart_toStartOf="parent"app:layout_constraintEnd_toEndOf="parent" /><TextViewandroid:id="@+id/resultTextView"android:layout_width="match_parent"android:layout_height="wrap_content"app:layout_constraintTop_toBottomOf="@id/recognizeButton"android:padding="16dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
悬浮窗功能实现
悬浮窗的功能主要实现上一句、当前句子、下一句的展示与复制。为了实现这个功能,我们可以使用 WindowManager 来创建一个悬浮窗,并在其中显示相应的句子。
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.TextView;public class FloatingWindowManager {private Context context;private WindowManager windowManager;private View floatingView;private TextView previousSentenceTextView;private TextView currentSentenceTextView;private TextView nextSentenceTextView;public FloatingWindowManager(Context context) {this.context = context;windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);createFloatingView();}private void createFloatingView() {LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);floatingView = inflater.inflate(R.layout.floating_window_layout, null);previousSentenceTextView = floatingView.findViewById(R.id.previousSentence);currentSentenceTextView = floatingView.findViewById(R.id.currentSentence);nextSentenceTextView = floatingView.findViewById(R.id.nextSentence);// 设置句子点击事件currentSentenceTextView.setOnClickListener(v -> {// 复制当前句子到剪贴板ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);ClipData clip = ClipData.newPlainText("sentence", currentSentenceTextView.getText());clipboard.setPrimaryClip(clip);});// 添加悬浮窗WindowManager.LayoutParams params = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT,WindowManager.LayoutParams.WRAP_CONTENT,WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,PixelFormat.TRANSLUCENT);params.gravity = Gravity.TOP | Gravity.LEFT; // 悬浮窗的位置params.x = 0;params.y = 100;windowManager.addView(floatingView, params);}public void updateSentences(String[] sentences, int currentIndex) {if (currentIndex > 0) {previousSentenceTextView.setText(sentences[currentIndex - 1]);}currentSentenceTextView.setText(sentences[currentIndex]);if (currentIndex < sentences.length - 1) {nextSentenceTextView.setText(sentences[currentIndex + 1]);}}
}
关系及绑定
在应用中,Fragment、ViewModel 和 View Binding 之间的关系如下:
- Fragment:负责管理 UI 和用户交互逻辑,通过
ViewModel获取和存储数据,使用View Binding直接访问布局中的视图。 - ViewModel:负责存储和管理与 UI 相关的数据,确保数据在生命周期变化时的持久性。
- View Binding:简化了视图的访问,提高了代码的安全性和可读性。
总结
通过使用 Fragment、ViewModel 和 View Binding,我们可以创建一个简化小说内容分享的应用。应用不仅提升了用户体验
,同时也展示了 Android 开发中这三者之间的紧密关系。希望这篇博客能够为你的 Android 开发之路提供一些启示!
