📌  相关文章
📜  如何在 Android 中构建一个简单的费用计算器应用程序?

📅  最后修改于: 2022-05-13 01:55:19.268000             🧑  作者: Mango

如何在 Android 中构建一个简单的费用计算器应用程序?

先决条件:

  • 面向初学者的 Android 应用开发基础知识
  • 安装和设置 Android Studio 指南
  • 如何在 Android Studio 中创建/启动新项目?
  • 运行您的第一个 Android 应用程序
  • Android 中的 RecyclerView 示例
  • Android 中的共享首选项示例

一个简单的费用计算器可让您以简化的方式添加收入和支出。这是我们将要构建的应用程序的一瞥。该应用程序包含一个带有 RecyclerView 的 Activity、两个 EditText(一个用于输入金额,另一个用于输入交易的简短说明)、1 个可单击的 TextView 以指定损失或收益、1 个可单击的图像以将交易添加到 RecyclerView,以及最后是一个自定义的 ActionBar 来显示余额。它包括在本地存储数据的共享首选项。下面给出了一个示例视频,以了解我们将在本文中做什么。请注意,我们将使用Java语言来实现这个项目。

分步实施

第 1 步:创建一个新项目

要在 Android Studio 中创建新项目,请参阅如何在 Android Studio 中创建/启动新项目。请注意,选择Java作为编程语言。

第2步:

在转到编码部分之前,让我们添加必要的依赖项。我们必须为项目添加的唯一依赖项是Gson 。它是一个Java库,可用于将Java对象转换为其 JSON 表示形式。它还可用于将 JSON字符串转换为等效的Java对象。转到应用级build.gradle文件并添加以下依赖项,然后单击立即同步。

implementation 'com.google.code.gson:gson:2.8.6'

这是一个参考,

第 3 步:

让我们添加必要的矢量资源和可绘制资源文件。转到app > res > drawable并添加以下 xml 文件。

ic_delete.xml (删除图标)

XML

  


XML

  


XML

    


XML


  
      
          
          
      
  
    
        
            
            
        
    


XML


  
    
  
    
  
    
    


XML


  
    
  
        
  
            
  
            
  
        
  
        
    
  
  


XML
                                                                                                        


Java
package com.cs.expensecalculator;  public class TransactionClass {    private int amount;    private String message;    private boolean positive;      public TransactionClass(int amount, String message, boolean positive) {        this.amount = amount;        this.message = message;        this.positive = positive;    }      public int getAmount() {        return amount;    }      public void setAmount(int amount) {        this.amount = amount;    }      public String getMessage() {        return message;    }      public void setMessage(String message) {        this.message = message;    }      public boolean isPositive() {        return positive;    }      public void setPositive(boolean positive) {        this.positive = positive;    }}


Java
package com.cs.expensecalculator;  import static com.cs.expensecalculator.MainActivity.calculateBalance;import static com.cs.expensecalculator.MainActivity.checkIfEmpty;import static com.cs.expensecalculator.MainActivity.setBalance;  import android.app.AlertDialog;import android.content.Context;import android.content.DialogInterface;import android.graphics.Color;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.ArrayList;  public class TransactionAdapter extends RecyclerView.Adapter {    Context ctx;        // List containing data for recyclerview    ArrayList transactionList;      // Constructor for TransactionAdapter    public TransactionAdapter(Context ctx, ArrayList transactionList) {        this.ctx = ctx;        this.transactionList = transactionList;    }      // On Create View Holder to Inflate transaction row layout    @NonNull    @Override    public TransactionAdapter.TViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {        View v = LayoutInflater.from(ctx).inflate(R.layout.transaction_row_layout,parent,false);        return new TransactionAdapter.TViewHolder(v);    }      @Override    public void onBindViewHolder(@NonNull TransactionAdapter.TViewHolder holder, int position) {                    // Setting Message to a TextView in Row Layout        holder.tvMessage.setText(transactionList.get(holder.getAdapterPosition()).getMessage());                   // If the transaction is Positive (Received Money) set Text Color to Green        if(transactionList.get(holder.getAdapterPosition()).isPositive())        {            holder.tvAmount.setTextColor(Color.parseColor("#00c853"));            // Setting Amount to a TextView in the row layout            holder.tvAmount.setText("+₹"+Integer.toString(transactionList.get(holder.getAdapterPosition()).getAmount()));        }                // If the transaction is Negative (Spent Money) set Text Color to Red        else {            holder.tvAmount.setTextColor(Color.parseColor("#F44336"));                           // Setting Amount to a TextView in the row layout            holder.tvAmount.setText("-₹"+Integer.toString(transactionList.get(holder.getAdapterPosition()).getAmount()));        }                  // On Click Listener for Delete Icon        holder.ivDelete.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                // Confirmation Alert to delete a Transaction                AlertDialog dialog = new AlertDialog.Builder(ctx)                        .setCancelable(false)                        .setTitle("Are you sure? The transaction will be deleted.")                        .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {                            @Override                            public void onClick(DialogInterface dialogInterface, int i) {                                dialogInterface.dismiss();                            }                        })                        .setPositiveButton("Ok", new DialogInterface.OnClickListener() {                            @Override                            public void onClick(DialogInterface dialogInterface, int i) {                                transactionList.remove(holder.getAdapterPosition());                                dialogInterface.dismiss();                                notifyDataSetChanged();                                checkIfEmpty(getItemCount());                                setBalance(transactionList);                            }                        })                        .create();                dialog.show();            }        });    }        // To get size of the list    @Override    public int getItemCount() {        return transactionList.size();    }      // View Holder for a Transaction    public static class TViewHolder extends RecyclerView.ViewHolder{        TextView tvAmount,tvMessage;        ImageView ivDelete;          public TViewHolder(@NonNull View itemView) {            super(itemView);            tvAmount = itemView.findViewById(R.id.tvAmount);            tvMessage = itemView.findViewById(R.id.tvMessage);            ivDelete = itemView.findViewById(R.id.ivDelete);        }    }}


Java
package com.cs.expensecalculator;  import androidx.appcompat.app.ActionBar;import androidx.appcompat.app.AppCompatActivity;import androidx.recyclerview.widget.LinearLayoutManager;import androidx.recyclerview.widget.RecyclerView;  import android.content.SharedPreferences;import android.graphics.Color;import android.os.Bundle;import android.provider.CalendarContract;import android.view.LayoutInflater;import android.view.View;import android.widget.EditText;import android.widget.ImageView;import android.widget.TextView;import android.widget.Toast;  import com.google.gson.Gson;import com.google.gson.reflect.TypeToken;  import java.lang.reflect.Type;import java.util.ArrayList;  public class MainActivity extends AppCompatActivity {    TextView tvSign;    public static TextView tvEmpty, tvBalance;    EditText etAmount, etMessage;    ImageView ivSend;    boolean positive = true;    RecyclerView rvTransactions;    TransactionAdapter adapter;    ArrayList transactionList;      // On create method    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);                  // Function to initialize views        initViews();                   // Function to load data from shared preferences        loadData();                    // Function to set custom action bar        setCustomActionBar();                    // To check if there is no transaction        checkIfEmpty(transactionList.size());          // Initializing recycler view        rvTransactions.setHasFixedSize(true);        rvTransactions.setLayoutManager(new LinearLayoutManager(this));        adapter = new TransactionAdapter(this,transactionList);        rvTransactions.setAdapter(adapter);          // On click sign change        tvSign.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                changeSign();            }        });          // On click Send        ivSend.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                  // Input Validation                if(etAmount.getText().toString().trim().isEmpty())                {                    etAmount.setError("Enter Amount!");                    return;                }                if(etMessage.getText().toString().isEmpty())                {                    etMessage.setError("Enter a message!");                    return;                }                try {                    int amt = Integer.parseInt(etAmount.getText().toString().trim());                                            // Adding Transaction to recycler View                    sendTransaction(amt,etMessage.getText().toString().trim(),positive);                    checkIfEmpty(transactionList.size());                                            // To update Balance                    setBalance(transactionList);                    etAmount.setText("");                    etMessage.setText("");                }                catch (Exception e){                    etAmount.setError("Amount should be integer greater than zero!");                }            }        });    }      // To set custom action bar    private void setCustomActionBar() {        this.getSupportActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);        getSupportActionBar().setDisplayShowCustomEnabled(true);        View v = LayoutInflater.from(this).inflate(R.layout.custom_action_bar,null);                    // TextView to show Balance        tvBalance = v.findViewById(R.id.tvBalance);                   // Setting balance        setBalance(transactionList);        getSupportActionBar().setCustomView(v);        getSupportActionBar().setElevation(0);    }      // To set Balance along with sign (spent(-) or received(+))    public static void setBalance(ArrayList transactionList){        int bal = calculateBalance(transactionList);        if(bal<0)        {            tvBalance.setText("- ₹"+calculateBalance(transactionList)*-1);        }        else {            tvBalance.setText("+ ₹"+calculateBalance(transactionList));        }    }      // To load data from shared preference    private void loadData() {        SharedPreferences pref = getSharedPreferences("com.cs.ec",MODE_PRIVATE);        Gson gson = new Gson();        String json = pref.getString("transactions",null);        Type type = new TypeToken>(){}.getType();        if(json!=null)        {            transactionList=gson.fromJson(json,type);        }    }      // To add transaction    private void sendTransaction(int amt,String msg, boolean positive) {        transactionList.add(new TransactionClass(amt,msg,positive));        adapter.notifyDataSetChanged();        rvTransactions.smoothScrollToPosition(transactionList.size()-1);    }      // Function to change sign    private void changeSign() {        if(positive)        {            tvSign.setText("-₹");            tvSign.setTextColor(Color.parseColor("#F44336"));            positive = false;        }        else {            tvSign.setText("+₹");            tvSign.setTextColor(Color.parseColor("#00c853"));            positive = true;        }    }      // To check if transaction list is empty    public static void checkIfEmpty(int size) {        if (size == 0)        {            MainActivity.tvEmpty.setVisibility(View.VISIBLE);        }        else {            MainActivity.tvEmpty.setVisibility(View.GONE);        }    }      // To Calculate Balance by iterating through all transactions    public static int calculateBalance(ArrayList transactionList)    {        int bal = 0;        for(TransactionClass transaction : transactionList)        {            if(transaction.isPositive())            {                bal+=transaction.getAmount();            }            else {                bal-=transaction.getAmount();            }        }        return bal;    }      // Initializing Views    private void initViews() {        transactionList = new ArrayList();        tvSign = findViewById(R.id.tvSign);        rvTransactions = findViewById(R.id.rvTransactions);        etAmount = findViewById(R.id.etAmount);        etMessage = findViewById(R.id.etMessage);        ivSend = findViewById(R.id.ivSend);        tvEmpty = findViewById(R.id.tvEmpty);    }      // Storing data locally       // using shared preferences    // in onStop() method    @Override    protected void onStop() {        super.onStop();        SharedPreferences.Editor editor = getSharedPreferences("com.cs.ec",MODE_PRIVATE).edit();        Gson gson = new Gson();        String json = gson.toJson(transactionList);        editor.putString("transactions",json);        editor.apply();    }}


预览:

ic_send.xml (发送图标)

XML


  

预览:

ic_balance.xml (钱包图标)

XML


    

预览:

etbg.xml (编辑文本选择器)

XML



  
      
          
          
      
  
    
        
            
            
        
    

这是一个截图供参考。

第4步:

现在让我们为自定义的 ActionBar 和 RecyclerView 行布局添加布局资源文件。转到app > res > layout并添加以下 xml 文件。下面是custom_action_bar .xml文件的代码。

XML



  
    
  
    
  
    
    

预览:

下面是transaction_row_layout .xml文件的代码。 (RecyclerView 行布局)

XML



  
    
  
        
  
            
  
            
  
        
  
        
    
  
  

预览:

这是一个截图供参考。

第 5 步:

我们已经为我们正在构建的应用程序添加了必要的资源文件。现在,让我们为我们的应用程序设计 UI。将此 xml 文件添加到app > res > 布局。下面是activity_main.xml文件的代码。