制作单词记录App(一)


本文为学习类文档,通过学习B站up主longway777的视频,再加上自己的总结与理解的学习类文章,如有侵权,请联系博主进行删除

制作单词记录App(一)

这次制作的单词记录App是根据前面学习的Room组件,migrantion等

修正性能上的小bug

在之前创建的MyAdapter中,针对词汇的点击跳转界面和开关隐藏中文意思,我们将点击事件放在了onBindViewHolder中,这个函数会被系统在运行过程中多次调用,会造成性能上的重复开销。
可以将其放在onCreateViewHolder中(创建一次即可)。

  1. 在onCreateViewHolder中定义itemView的ViewHolder对象
final MyViewHolder holder = new MyViewHolder(itemView);
  1. 调用holder的点击事件方法(处理word在创建时无法获取)
    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
       ...
        final MyViewHolder holder = new MyViewHolder(itemView);
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Uri uri = Uri.parse("http://dict.youdao.com/w/" + holder.textViewEnglish.getText() + "/#keyfrom=dict2.top");
                Intent intent = new Intent(Intent.ACTION_VIEW);
                intent.setData(uri);
                holder.itemView.getContext().startActivity(intent);
            }
        });

        holder.aSwitchChineseInvisible.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                Word word = (Word) holder.itemView.getTag(R.id.word_for_view_holder);//广义object要强制转换
                if (isChecked) {
                    holder.textViewChinese.setVisibility(View.GONE);
                    word.setChineseInvisible(true);
                    wordViewModel.updateWords(word);
                } else {
                    holder.textViewChinese.setVisibility(View.VISIBLE);
                    word.setChineseInvisible(false);
                    wordViewModel.updateWords(word);
                }
            }
        });

        return holder;  //改为返回holder类型
    }
  1. 在onBindViewHolder中定义word的itemView的setTag()方法(方便用户在create中使用getTag()方法获取数据。)
//itemView的setTag方法可以获取对象并在其他地方通过getTag获取对应对象
        holder.itemView.setTag(R.id.word_for_view_holder,word); 
  1. 为了保证setTag在整个项目中保证全局唯一特性,设置int型参数,可以通过创建资源类将id存入以保证不冲突:
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <item name="word_for_view_holder" type="id"/>
</resources>
  1. 运行之后无变化,性能提高

开始制作新单词界面

  1. 创建两个fragement用来显示添加界面和单词显示界面
  2. 创建资源类navigation文件并链接两个fragement(wordfragement、addfragement),创建两者的动作联系。(可以自己选择制作进出动画)
  3. 在Activity中删除之前创建的控件并导入NavHostFragement入口(在container控件中)完成系统链接
  4. 在wordfragement搭建界面,放入一个recyclerView
  5. 填写wordfragement关联代码
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelProviders;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.Adapter;
import java.util.List;


/**
 * A simple {@link Fragment} subclass.
 */
public class WordsFragment extends Fragment {
    private WordViewModel wordViewModel;
    private RecyclerView recyclerView;
    private MyAdapter myAdapter1,myAdapter2;


    public WordsFragment() {
        // Required empty public constructor
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_words, container, false);
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        wordViewModel = new ViewModelProvider(requireActivity()).get(WordViewModel.class);
        recyclerView = requireActivity().findViewById(R.id.recyclerView);
        recyclerView.setLayoutManager(new LinearLayoutManager(requireActivity()));
        myAdapter1 = new MyAdapter(false, wordViewModel);//第一个布局不适用卡片布局,所以为false
        myAdapter2 = new MyAdapter(true,wordViewModel);
        recyclerView.setAdapter(myAdapter1);
        wordViewModel.getAllWordsLive().observe(requireActivity(), new Observer<List<Word>>() {
            @Override
            public void onChanged(List<Word> words) {
                int temp = myAdapter1.getItemCount();
                myAdapter1.setAllWords(words);
                myAdapter2.setAllWords(words);
                if (temp!=words.size()) {
                    myAdapter1.notifyDataSetChanged();
                    myAdapter2.notifyDataSetChanged();
                }
            }
        });
    }
}
  1. 删除之前在MainActivity中的代码并准备重写MainActivity代码(此处不该写也能运行之前制作的界面,原因是将activity中的大部分代码功能移植到了fragement中)
  2. 在wordsFragement中制作添加按键(使用自带的FloatingActionButton)
    创建矢量图标res->new->Vector Asset,选择add图标,背景色为白色,并创建。
    将FloatingActionButton拖动到界面中,并设置它的Layout_gravity(Bottom——true,CenterHorizontal——true)属性和Layout_margin属性
  3. 补充wordsFragement代码:
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelProviders;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.Adapter;

import com.google.android.material.floatingactionbutton.FloatingActionButton;

import java.util.List;


/**
 * A simple {@link Fragment} subclass.
 */
public class WordsFragment extends Fragment {
...
    private FloatingActionButton floatingActionButton; //定义变量
...
    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        ...
        floatingActionButton = requireActivity().findViewById(R.id.floatingActionButton);
        floatingActionButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                NavController navController = Navigation.findNavController(v);
                navController.navigate(R.id.action_wordsFragment_to_addFragment);
            }
        });
    }
}
  1. 在导航条设置返回按键:
import androidx.appcompat.app.AppCompatActivity;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import androidx.navigation.ui.NavigationUI;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {
    private NavController navController;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        navController = Navigation.findNavController(findViewById(R.id.fragment));
        NavigationUI.setupActionBarWithNavController(this,navController);
    }

    @Override
    public boolean onSupportNavigateUp() {
        navController.navigateUp();
        return super.onSupportNavigateUp();
    }
}

  1. 修改Fragement的Lable
  2. Add页面的制作:
    在这里插入图片描述
<?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/frameLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".AddFragment" >

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="添加单词"
        android:textSize="24sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.1" />

    <EditText
        android:id="@+id/editTextEnglish"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        android:ems="10"
        android:hint="English Word"
        android:inputType="textPersonName"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.2" />

    <EditText
        android:id="@+id/editTextChinese"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        android:ems="10"
        android:hint="中文释义"
        android:inputType="textPersonName"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.3" />

    <Button
        android:id="@+id/buttonSubmit"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.4" />
</androidx.constraintlayout.widget.ConstraintLayout>
  1. Add界面逻辑代码:
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;


 /**
 * A simple {@link Fragment} subclass.
 */
public class AddFragment extends Fragment {
    private Button buttonSubmit;
    private EditText editTextEnglish,editTextChinese;
    private WordViewModel wordViewModel;


    public AddFragment() {
        // Required empty public constructor
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_add, container, false);
    }

     @Override
     public void onActivityCreated(@Nullable Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);

         wordViewModel = new ViewModelProvider(requireActivity()).get(WordViewModel.class);
         buttonSubmit = requireActivity().findViewById(R.id.buttonSubmit);
         editTextEnglish = requireActivity().findViewById(R.id.editTextEnglish);
         editTextChinese = requireActivity().findViewById(R.id.editTextChinese);
         //有效信息不足时,按键设置为灰色状态
         buttonSubmit.setEnabled(false);
         //进入界面即可弹出键盘以节省操作,人性化体现
         editTextEnglish.requestFocus();//光标获取焦点
         InputMethodManager imm = (InputMethodManager) requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
         imm.showSoftInput(editTextEnglish,0);//强制显示键盘,两个参数为(1. 关联的View;2. flag)
         //制作edit监听器
         TextWatcher textWatcher = new TextWatcher() {
             @Override
             public void beforeTextChanged(CharSequence s, int start, int count, int after) {

             }

             @Override
             public void onTextChanged(CharSequence s, int start, int before, int count) {
                 String english = editTextEnglish.getText().toString().trim();
                 String chinese = editTextChinese.getText().toString().trim();
                 buttonSubmit.setEnabled(!english.isEmpty() && !chinese.isEmpty());
             }

             @Override
             public void afterTextChanged(Editable s) {

             }
         };
         //添加到edit中
         editTextEnglish.addTextChangedListener(textWatcher);
         editTextChinese.addTextChangedListener(textWatcher);
         //设置按键监听器,将数据存储到数据库中,并返回word界面
         buttonSubmit.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
                 String english = editTextEnglish.getText().toString().trim();
                 String chinese = editTextChinese.getText().toString().trim();
                 Word word = new Word(english,chinese);
                 wordViewModel.insertWords(word); //数据添加
                 NavController navController = Navigation.findNavController(v);
                 navController.navigateUp();
                 //返回界面时隐藏键盘的操作
                 InputMethodManager imm = (InputMethodManager) requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
                 imm.hideSoftInputFromWindow(v.getWindowToken(),0);//两个参数
             }
         });
     }
 }
  1. 处理因键盘弹出而自动压缩界面的操作:
    在清单文件中设置activity的windowSoftInputMode=“adjustNothing”——不做任何调整:
<activity android:name="com.example.words.MainActivity"
            android:windowSoftInputMode="adjustNothing">
  1. 处理因点击返回自设按键键盘不收回的设置:
    在MainActivity中的onSupportNavigateUp()中补充代码:
@Override
    public boolean onSupportNavigateUp() {
        //返回界面时隐藏键盘的操作
        InputMethodManager imm = (InputMethodManager) this.getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(findViewById(R.id.fragment).getWindowToken(),0);//两个参数
        navController.navigateUp();
        return super.onSupportNavigateUp();
    }
  1. 运行后可以将自己添加的单词释义加入其中:
    在这里插入图片描述
    在这里插入图片描述
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值