Android安卓实战项目(13)---记账APP详细记录每天的收入和支出并且分类统计【生活助手类APP】强烈推荐自己也在用!!!(源码在文末🐕🐕🐕)
一.项目运行介绍
B站视频链接:
【Android安卓实战项目(13)---记账APP详细记录每天的收入和支出并且分类统计【生活助手类APP】强烈推荐自己也在用!!!(源码在文末🐕🐕🐕)】
1.开机动画
2.主页面展示
3.支出记录页面展示
4.收入记录页面展示
5.总交易流程展示
6.显示余额
7.添加备注
二.具体实现
1.MainActivity.java
package com.yuukidach.ucount;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.net.Uri;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.ItemTouchHelper;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.yuukidach.ucount.view.adapter.BookItemAdapter;
import com.yuukidach.ucount.view.adapter.MoneyItemAdapter;
import com.yuukidach.ucount.callback.BookItemCallback;
import com.yuukidach.ucount.callback.MainItemCallback;
import com.yuukidach.ucount.model.BookItem;
import com.yuukidach.ucount.model.ImgUtils;
import com.yuukidach.ucount.model.MoneyItem;
import com.yuukidach.ucount.presenter.MainPresenter;
import com.yuukidach.ucount.view.MainView;
import java.text.DecimalFormat;
import java.util.List;
import at.markushi.ui.CircleButton;
public class MainActivity extends AppCompatActivity implements MainView {
private final ImgUtils imgUtils = new ImgUtils(this);
private final MainPresenter mainPresenter = new MainPresenter(this, imgUtils);
private Button showBtn;
private ImageButton statsBtn;
private TextView monthlyCost;
private TextView monthlyEarn;
private ImageView headerImg;
private RecyclerView MoneyItemRecyclerView;
// parameter for drawer
private DrawerLayout drawerLayout;
private LinearLayout bookLinearLayout;
private RecyclerView bookItemRecyclerView;
private ImageView drawerBanner;
public static String PACKAGE_NAME;
public static Resources resources;
public DecimalFormat decimalFormat = new DecimalFormat("0.00");
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(R.style.AppTheme);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 获得包名和资源,方便后面的程序使用
PACKAGE_NAME = getApplicationContext().getPackageName();
resources = getResources();
showBtn = (Button) findViewById(R.id.show_money_button);
statsBtn = (ImageButton) findViewById(R.id.stats_button);
monthlyCost = (TextView) findViewById(R.id.monthly_cost_money);
monthlyEarn = (TextView) findViewById(R.id.monthly_earn_money);
headerImg = (ImageView) findViewById(R.id.header_img);
CircleButton addBtn = (CircleButton) findViewById(R.id.add_button);
ImageButton addBookButton = (ImageButton) findViewById(R.id.add_book_button);
MoneyItemRecyclerView = (RecyclerView) findViewById(R.id.in_and_out_items);
// drawer
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_of_books);
bookItemRecyclerView = (RecyclerView) findViewById(R.id.book_list);
bookLinearLayout = (LinearLayout) findViewById(R.id.left_drawer);
drawerBanner = (ImageView) findViewById(R.id.drawer_banner);
showBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String str = showBtn.getText().toString();
mainPresenter.onShowBalanceClick(str);
}
});
// start activity to add cost or earning item
addBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
navigateToAddItem();
}
});
// start activity to statistics
statsBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
navigateToStatistics();
}
});
addBookButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mainPresenter.onAddBookClick();
}
});
// 设置首页header图片长按以更换图片
headerImg.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
mainPresenter.onImageLongClick(ImageType.HEADER);
return false;
}
});
drawerBanner.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
mainPresenter.onImageLongClick(ImageType.DRAWER);
return false;
}
});
}
@Override
protected void onResume() {
super.onResume();
mainPresenter.onResume();
}
@Override
public void onBackPressed() {
Intent intent = new Intent(Intent.ACTION_MAIN); // ACTION_MAIN 作为Task中第一个Activity启动
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addCategory(Intent.CATEGORY_HOME); // CATEGORY_HOME 设备启动时的第一个Activity
startActivity(intent);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (data == null) return;
Uri uri = data.getData();
mainPresenter.onActivityResult(uri, requestCode);
// get permanent permission to access the image
int takeFlags = data.getFlags()
& (Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
getContentResolver().takePersistableUriPermission(uri, takeFlags);
}
@Override
public void openPicGallery(ImageType type) {
Log.d(TAG, "openPicGallery: " + type.ordinal());
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.setType("image/*");
startActivityForResult(intent, type.ordinal());
}
@Override
public void updateHeaderImg(String uriStr) {
// If there is no picture in SharedPreferences, then use default picture
if (uriStr.isEmpty()) return;
Uri uri = Uri.parse(uriStr);
this.headerImg.setImageURI(uri);
}
@Override
public void updateDrawerImg(String uriStr) {
// If there is no picture in SharedPreferences, then use default picture
if (uriStr.isEmpty()) return;
Uri uri = Uri.parse(uriStr);
this.drawerBanner.setImageURI(uri);
}
@Override
public void showBalance(String numStr) {
showBtn.setText(numStr);
}
@Override
public void hideBalance() {
showBtn.setText(R.string.show_balance);
}
@Override
public void updateMonthlyEarn(String numStr) {
monthlyEarn.setText(numStr);
}
@Override
public void updateMonthlyCost(String numStr) {
monthlyCost.setText(numStr);
}
@Override
public void navigateToAddItem() {
Intent intent = new Intent(MainActivity.this, AddItemActivity.class);
Bundle bundle = new Bundle();
// tell addItemActivity which book is on
bundle.putInt("bookId", mainPresenter.getCurBookId());
intent.putExtras(bundle);
startActivity(intent);
}
@Override
public void setMainItemRecycler(List<MoneyItem> list) {
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setStackFromEnd(true); // show from bottom to top
layoutManager.setReverseLayout(true); // reverse the layout
MoneyItemAdapter moneyItemAdapter = new MoneyItemAdapter(mainPresenter, list);
MoneyItemRecyclerView.setAdapter(moneyItemAdapter);
MoneyItemRecyclerView.setLayoutManager(layoutManager);
ItemTouchHelper ioTouchHelper = new ItemTouchHelper(
new MainItemCallback(this, MoneyItemRecyclerView, moneyItemAdapter)
);
ioTouchHelper.attachToRecyclerView(MoneyItemRecyclerView);
}
@Override
public void setBookItemRecycler(List<BookItem> list) {
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
bookItemRecyclerView.setLayoutManager(layoutManager);
bookItemRecyclerView.addItemDecoration(
new DividerItemDecoration(this, DividerItemDecoration.VERTICAL)
);
BookItemAdapter bookAdapter = new BookItemAdapter(mainPresenter);
bookAdapter.setOnItemClickListener(new BookItemAdapter.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
mainPresenter.updateBookItemView(position);
drawerLayout.closeDrawer(bookLinearLayout);
onResume();
}
});
bookItemRecyclerView.setAdapter(bookAdapter);
ItemTouchHelper bookTouchHelper = new ItemTouchHelper(
new BookItemCallback(this, bookItemRecyclerView, bookAdapter)
);
bookTouchHelper.attachToRecyclerView(bookItemRecyclerView);
}
@Override
public void setNewBook() {
final EditText book_title = new EditText(MainActivity.this);
// 弹窗输入
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setMessage(R.string.new_book_prompt);
builder.setView(book_title);
builder.setPositiveButton(R.string.confirm, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (!book_title.getText().toString().isEmpty()) {
mainPresenter.onAddBookConfirmClick(book_title.getText().toString());
onResume();
} else {
// TODO: use strings.xml
Toast.makeText(getApplicationContext(), "没有输入新账本名称哦", Toast.LENGTH_SHORT).show();
}
}
}).setNegativeButton(R.string.cancle, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
}).show();
}
@Override
public void navigateToStatistics() {
Intent intent = new Intent(MainActivity.this, StatisticsActivity.class);
Bundle bundle = new Bundle();
// tell StatisticsActivity which book is on
bundle.putInt("bookId", mainPresenter.getCurBookId());
intent.putExtras(bundle);
startActivity(intent);
}
}
-
onCreate
方法:这是活动的主要入口点,在活动创建时调用。在这里,活动的布局文件被加载,界面上的视图元素被初始化,并设置了各种点击事件的监听器。
setTheme(R.style.AppTheme)
:设置活动的主题样式。setContentView(R.layout.activity_main)
:加载布局文件以显示界面。- 初始化各个视图元素,如
showBtn
、statsBtn
、monthlyCost
等。
-
按钮点击事件:
showBtn.setOnClickListener
:设置 "显示余额" 按钮的点击事件监听器。点击按钮会触发onShowBalanceClick
方法,该方法会调用mainPresenter
的相应方法来处理逻辑。addBtn.setOnClickListener
:设置 "添加" 按钮的点击事件监听器。点击按钮会打开一个新的界面以添加记账项。statsBtn.setOnClickListener
:设置 "统计" 按钮的点击事件监听器。点击按钮会打开一个统计界面。
-
图片长按事件:
headerImg.setOnLongClickListener
:设置头部图片的长按事件监听器。长按图片会触发更换图片的操作。drawerBanner.setOnLongClickListener
:设置侧边栏图片的长按事件监听器。长按图片会触发更换侧边栏图片的操作。
-
onResume
方法:当活动从暂停状态恢复时(例如从后台返回前台),
onResume
方法会被调用。在这里,调用了mainPresenter.onResume()
,用于处理活动的恢复逻辑。 -
onBackPressed
方法:当用户按下后退按钮时,该方法会被调用。在这里,创建一个意图以返回到设备的主屏幕。
-
onActivityResult
方法:当从其他活动返回结果时,
onActivityResult
方法会被调用。在这里,根据返回的数据,调用了mainPresenter
的相应方法来处理图片操作。 -
openPicGallery
方法:用于打开图片库以选择图片。
-
图片更新方法:
updateHeaderImg
:用于更新头部图片。updateDrawerImg
:用于更新侧边栏图片。
-
showBalance
和hideBalance
方法:用于显示和隐藏余额。
-
余额和统计信息更新方法:
updateMonthlyEarn
:用于更新每月收入信息。updateMonthlyCost
:用于更新每月支出信息。
-
导航方法:
navigateToAddItem
:用于导航到添加记账项的界面。navigateToStatistics
:用于导航到统计界面。
-
setMainItemRecycler
和setBookItemRecycler
方法:用于设置记账项列表和账本列表的适配器和布局管理器。
-
setNewBook
方法:弹出对话框,允许用户输入新的账本名称,并在确认后创建一个新账本。
以上是对主要部分的详细解释,这段代码涵盖了Android应用程序中常见的UI交互和逻辑处理。它包含了处理点击事件、图片操作、界面导航以及适配器和布局管理器的使用等内容。
2.AddItemActivity.java
package com.yuukidach.ucount;
import android.content.Intent;
import android.graphics.Typeface;
import android.os.Bundle;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.yuukidach.ucount.model.MoneyItem;
import com.yuukidach.ucount.presenter.AddItemPresenter;
import com.yuukidach.ucount.view.AddItemView;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Locale;
public class AddItemActivity extends AppCompatActivity implements AddItemView {
private final int REQUEST_DESCRIPTION = 1;
private AddItemPresenter presenter;
private static final String TAG = "AddItemActivity";
private FragmentManager manager;
private FragmentTransaction transaction;
private Button addCostBtn;
private Button addEarnBtn;
private Button clearBtn;
private ImageButton addFinishBtn;
private ImageButton addDescription;
private ImageView bannerImage;
private TextView bannerText;
private TextView moneyText;
private TextView words;
private SimpleDateFormat formatItem = new SimpleDateFormat("yyyy年MM月dd日", Locale.CHINA);
private SimpleDateFormat formatSum = new SimpleDateFormat("yyyy年MM月", Locale.CHINA);
private DecimalFormat decimalFormat = new DecimalFormat("0.00");
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_item);
addCostBtn = (Button) findViewById(R.id.add_cost_button);
addEarnBtn = (Button) findViewById(R.id.add_earn_button);
addFinishBtn = (ImageButton) findViewById(R.id.add_finish);
addDescription = (ImageButton) findViewById(R.id.add_description);
clearBtn = (Button) findViewById(R.id.clear);
words = (TextView) findViewById(R.id.anime_words);
// 设置字体颜色
Typeface typeface = Typeface.createFromAsset(getAssets(), "fonts/chinese_character.ttf");
clearBtn.setTypeface(typeface);
words.setTypeface(typeface);
Bundle bundle = getIntent().getExtras();
presenter = new AddItemPresenter(this, bundle.getInt("bookId"));
bannerText = (TextView) findViewById(R.id.chosen_title);
bannerImage = (ImageView) findViewById(R.id.chosen_image);
moneyText = (TextView) findViewById(R.id.input_money_text);
presenter.onCreate();
addCostBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
presenter.onAddCostButtonClick();
}
});
addEarnBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
presenter.onAddEarnButtonClick();
}
});
addFinishBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
presenter.onAddFinishButtonClick();
finish();
}
});
clearBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
presenter.onClearButtonClick();
}
});
addDescription.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
presenter.onDescriptionButtonClick();
}
});
}
// 数字输入按钮
public void calculatorNumOnclick(View v) {
presenter.OnNumPadNumClick(v);
}
// 小数点处理工作
public void calculatorPushDot(View view) {
presenter.onNumPadDotClock();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_DESCRIPTION) {
if (resultCode == RESULT_OK) {
presenter.setDescription(data.getStringExtra(Intent.EXTRA_TEXT));
}
}
}
@Override
public void highlightEarnButton() {
addCostBtn.setTextColor(0xff908070); // set cost button as gray
addEarnBtn.setTextColor(0xffff8c00); // set earn button as orange
}
@Override
public void highlightCostButton() {
addEarnBtn.setTextColor(0xff908070); // set earn button as gray
addCostBtn.setTextColor(0xffff8c00); // set cost button as orange
}
@Override
public void setAmount(String numStr) {
moneyText.setText(numStr);
}
@Override
public void useEarnFragment() {
transaction.replace(R.id.item_fragment, new EarnFragment());
}
@Override
public void useCostFragment() {
transaction.replace(R.id.item_fragment, new CostFragment());
}
@Override
public void setupTransaction() {
manager = getSupportFragmentManager();
beginTransaction();
transaction.replace(R.id.item_fragment, new CostFragment());
endTransaction();
}
@Override
public void beginTransaction() {
transaction = manager.beginTransaction();
}
@Override
public void endTransaction() {
transaction.commit();
}
@Override
public String getMoney() {
return moneyText.getText().toString();
}
@Override
public void navigateToDescription() {
Intent intent = new Intent(AddItemActivity.this, DescriptionActivity.class);
Bundle bundle = new Bundle();
bundle.putString("description", presenter.getDescription());
intent.putExtras(bundle);
startActivityForResult(intent, REQUEST_DESCRIPTION);
}
@Override
public void alarmNoMoneyInput() {
Toast.makeText(getApplicationContext(),"唔姆,你还没输入金额",Toast.LENGTH_SHORT).show();
}
@Override
public void alarmCanNotContinueToInput() {
Toast.makeText(getApplicationContext(), "唔,已经不能继续输入了", Toast.LENGTH_SHORT).show();
}
@Override
public void alarmAlreadyHasDot() {
Toast.makeText(getApplicationContext(), "已经输入过小数点了 ━ω━●", Toast.LENGTH_SHORT).show();
}
@Override
public String getTypeName() {
return bannerText.getText().toString();
}
@Override
public String getTypeImgResourceName() {
return bannerText.getTag().toString();
}
@Override
public MoneyItem.InOutType getInOutFlag() {
Log.d(TAG, "getInOutFlag: " + (MoneyItem.InOutType)bannerImage.getTag());
return (MoneyItem.InOutType) bannerImage.getTag();
}
@Override
public String getPressedNumPadValue(View view) {
Button button = (Button) view;
return button.getText().toString();
}
}
逐步详细地介绍这段代码:
-
导入必要的类和库:代码一开始通过
import
语句导入了许多类,这些类用于构建Android应用界面、处理数据和逻辑等。其中一些重要的类包括android.content.Intent
用于活动间的数据传递,androidx.fragment.app.FragmentManager
和androidx.fragment.app.FragmentTransaction
用于管理Fragment,android.widget.*
用于处理各种UI元素,以及自定义的类如com.yuukidach.ucount.model.MoneyItem
和com.yuukidach.ucount.presenter.AddItemPresenter
。 -
定义常量和变量:在代码中定义了一些常量和实例变量,如
REQUEST_DESCRIPTION
是一个用于识别意图的请求代码,AddItemPresenter
是一个处理视图和数据之间交互的Presenter,还有各种按钮、图像、文本视图等。 -
设置界面布局:在
onCreate
方法中,通过setContentView
方法将活动的界面布局设置为 "activity_add_item.xml"。这个布局文件描述了活动的用户界面,定义了各种UI元素的位置和交互方式。 -
初始化UI元素:接下来,通过
findViewById
方法获取在布局文件中定义的各种UI元素,如按钮、图像、文本视图等。然后对这些UI元素进行一些设置,例如:setTypeface
方法用于为按钮设置自定义字体样式,增加了一些视觉效果。setTextColor
方法用于设置按钮文本的颜色,以区分不同的按钮状态。
-
获取传递的数据:通过
getIntent().getExtras()
获取从前一个活动传递过来的额外数据,这里通过键名 "bookId" 获取一个整数值,然后用这个值初始化了AddItemPresenter
。 -
设置按钮点击事件:通过监听按钮的点击事件,为按钮添加了点击响应的逻辑。例如,
addCostBtn
按钮点击时会调用presenter.onAddCostButtonClick()
方法。 -
实现接口方法:这个活动实现了一个接口
AddItemView
,这个接口定义了一系列用于与Presenter交互的方法。这些方法用于更新界面、处理用户输入等操作。 -
其他方法:代码中还有一些其他方法,用于处理数字输入、小数点操作、启动其他活动、显示提示信息等。
总之,这段代码实现了一个用于记录金钱交易的Android活动。它通过获取用户输入、点击按钮、调用Presenter等方式,交互地在界面上显示交易细节,并将数据传递给Presenter进行进一步处理。
3.StatisticsActivity.java
package com.yuukidach.ucount;
import android.database.Cursor;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageButton;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.github.mikephil.charting.charts.PieChart;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.data.PieData;
import com.github.mikephil.charting.data.PieDataSet;
import com.github.mikephil.charting.data.PieEntry;
import com.yuukidach.ucount.model.MoneyItem;
import com.yuukidach.ucount.presenter.StatisticsPresenter;
import com.yuukidach.ucount.view.StatisticsView;
import org.litepal.LitePal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;
public class StatisticsActivity extends AppCompatActivity implements StatisticsView {
private static final String TAG = "StatisticsActivity";
private StatisticsPresenter presenter;
private TextView selectText;
private Calendar calendar;
private String yearMonth;
private SimpleDateFormat fmtYM;
private final int[] PIE_COLORS={
Color.rgb(181, 194, 202), Color.rgb(129, 216, 200), Color.rgb(241, 214, 145),
Color.rgb(108, 176, 223), Color.rgb(195, 221, 155), Color.rgb(251, 215, 191),
Color.rgb(237, 189, 189), Color.rgb(172, 217, 243)
};
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_statistics);
ImageButton prevBtn = (ImageButton) findViewById(R.id.prev_month);
ImageButton nextBtn = (ImageButton) findViewById(R.id.next_month);
selectText = (TextView) findViewById(R.id.selected_month);
Bundle bundle = getIntent().getExtras();
presenter = new StatisticsPresenter(this, bundle.getInt("bookId"));
presenter.onCreate();
fmtYM = new SimpleDateFormat("yyyy-MM", Locale.getDefault());
calendar = Calendar.getInstance();
yearMonth = fmtYM.format(calendar.getTime());
selectText.setText(yearMonth);
Log.d("calendar", "format:"+ yearMonth);
drawPieChart();
prevBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
presenter.onPrevButtonClick();
}
});
nextBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
presenter.onNextButtonClick();
}
});
}
@Override
public void prevMonth() {
calendar.add(Calendar.MONTH, -1);
yearMonth = fmtYM.format(calendar.getTime());
Log.d("calendar", "format:"+ fmtYM.format(calendar.getTime()));
selectText.setText(yearMonth);
}
@Override
public void nextMonth() {
calendar.add(Calendar.MONTH, 1);
yearMonth = fmtYM.format(calendar.getTime());
Log.d("calendar", "format:"+ fmtYM.format(calendar.getTime()));
selectText.setText(yearMonth);
}
@Override
public void selectMonth() {
}
@Override
public void drawPieChart() {
PieChart chart_cost = (PieChart) findViewById(R.id.chart_cost);
PieChart chart_earn = (PieChart) findViewById(R.id.chart_earn);
List<PieEntry> entries_cost = new ArrayList<PieEntry>();
List<PieEntry> entries_earn = new ArrayList<PieEntry>();
Cursor cursor_cost = LitePal.findBySQL("select sum(money),typename from MoneyItem " +
"where bookId = ? and " +
"inOutType = ? and " +
"date like ? " +
"group by typename", String.valueOf(presenter.getBookId()), MoneyItem.InOutType.COST.toString(), yearMonth+"%");
Cursor cursor_earn = LitePal.findBySQL("select sum(money),typename from MoneyItem " +
"where bookId = ? and " +
"inOutType = ? and " +
"date like ? " +
"group by typename", String.valueOf(presenter.getBookId()), MoneyItem.InOutType.EARN.toString(), yearMonth+"%");
if (cursor_cost != null && cursor_cost.moveToFirst()) {
do {
Log.d("database", "#######"+cursor_cost.getString(1)+"########");
Log.d("database", "#######"+cursor_cost.getDouble(0)+"########");
entries_cost.add(new PieEntry((float) cursor_cost.getDouble(cursor_cost.getColumnIndex("sum(money)")),
cursor_cost.getString(cursor_cost.getColumnIndex("typename"))));
} while (cursor_cost.moveToNext());
}
if (cursor_earn != null && cursor_earn.moveToFirst()) {
do {
Log.d("database", "#######"+cursor_earn.getString(1)+"########");
Log.d("database", "#######"+cursor_earn.getDouble(0)+"########");
entries_earn.add(new PieEntry((float) cursor_earn.getDouble(cursor_earn.getColumnIndex("sum(money)")),
cursor_earn.getString(cursor_earn.getColumnIndex("typename"))));
} while (cursor_earn.moveToNext());
}
PieDataSet dataSet_cost = new PieDataSet(entries_cost, "");
dataSet_cost.setColors(PIE_COLORS);
dataSet_cost.setValueLinePart1OffsetPercentage(60f);
dataSet_cost.setYValuePosition(PieDataSet.ValuePosition.OUTSIDE_SLICE);
dataSet_cost.setValueLinePart1Length(0.4f);
dataSet_cost.setValueLinePart2Length(0.4f);
PieData pieData_cost = new PieData(dataSet_cost);
pieData_cost.setValueTextSize(18f);
Legend l = chart_cost.getLegend();
l.setTextSize(15f);
l.setFormSize(12f);
l.setXEntrySpace(10f);
chart_cost.setData(pieData_cost);
chart_cost.getDescription().setText("");
chart_cost.setExtraOffsets(10f, 0, 10f, 0);
chart_cost.setEntryLabelColor(0xff000000);
chart_cost.setEntryLabelTextSize(15f);
chart_cost.invalidate();
PieDataSet dataSet_earn = new PieDataSet(entries_earn, "");
dataSet_earn.setColors(PIE_COLORS);
dataSet_earn.setValueLinePart1OffsetPercentage(60f);
dataSet_earn.setYValuePosition(PieDataSet.ValuePosition.OUTSIDE_SLICE);
dataSet_earn.setValueLinePart1Length(0.4f);
dataSet_earn.setValueLinePart2Length(0.4f);
PieData pieData_earn = new PieData(dataSet_earn);
pieData_earn.setValueTextSize(18f);
l = chart_earn.getLegend();
l.setTextSize(15f);
l.setFormSize(12f);
l.setXEntrySpace(10f);
chart_earn.setData(pieData_earn);
chart_earn.getDescription().setText("");
chart_earn.setExtraOffsets(10f, 0, 10f, 0);
chart_earn.setEntryLabelColor(0xff000000);
chart_earn.setEntryLabelTextSize(15f);
chart_earn.invalidate();
}
}
这段代码是一个名为 "StatisticsActivity" 的 Android 应用程序组件,主要用于展示统计数据并绘制饼状图。我将逐步解释代码的各个部分:
-
导入包和库:
- 代码开始处导入了必要的 Android 类和第三方库,用于在应用中使用图表和数据库功能。
-
类定义和成员变量:
StatisticsActivity
类继承自AppCompatActivity
,表示这是一个与界面交互的 Activity。- 成员变量包括
TAG
(用于日志输出)、presenter
(用于处理界面逻辑和数据交互)、selectText
(用于显示所选月份)、calendar
(用于日期计算)、yearMonth
(表示所选年月字符串)、fmtYM
(日期格式化工具)以及PIE_COLORS
(饼图颜色数组)等。
-
onCreate 方法:
- 这是 Activity 的生命周期方法,会在创建时调用。
- 设置布局和获取界面元素的引用。
- 通过
getIntent().getExtras()
获取从上一个 Activity 传递的参数,并用该参数初始化presenter
。 - 初始化日期格式化工具和当前日期,并在界面上显示。
- 调用
drawPieChart
方法绘制饼图。 - 为前进和后退按钮设置点击监听器,用于在不同月份之间切换。
-
接口方法的实现 (
StatisticsView
接口的实现):prevMonth()
:向前切换一个月份,更新日期并在界面上显示。nextMonth()
:向后切换一个月份,更新日期并在界面上显示。selectMonth()
:暂时空实现,用于选择月份。drawPieChart()
:绘制两个饼图,分别用于显示支出和收入的数据。
-
绘制饼图方法
drawPieChart
:- 获取两个
PieChart
控件的引用,分别表示支出和收入饼图。 - 通过 SQL 查询从数据库中获取特定月份、特定账本和特定类型(支出或收入)的数据,然后将查询结果存储到
entries_cost
和entries_earn
列表中。 - 创建
PieDataSet
对象,并将查询结果添加到数据集中。 - 配置数据集的样式、值的位置等参数。
- 创建
PieData
对象,并设置数据集。 - 配置图例的样式,然后将数据集绑定到饼图控件上并刷新显示。
- 获取两个
三.项目源码
链接:https://pan.baidu.com/s/1wlzPw6kJV_4kSHv-lQPyVw
提取码:****
创作不易,项目已加密,有偿(仅一杯奶茶钱,可做实验报告,代码讲解等...)
请私信作者或
(v)15135757306