1.Android平台随心明信片系统需求分析
1.1.数据库设计
根据程序设计,本系统设计了用户信息表,相册信息表,相片信息表,明显片表等四张数据库表
1.1.1.表users结构
用户信息表,包括用户ID,用户名和密码
名称 代码 数据类型 长度 注释
编号 id int(11) 11
用户名 name varchar(255) 255
密码 password varchar(255) 255
1.1.2.表galleryname结构
相册信息表,包括相册ID,相册名称,用户ID。
名称 代码 数据类型 长度 注释
编号 id int(11) 11
相册名称 name varchar(255) 255
用户ID userid varchar(255) 255
1.1.3.表galleries结构
相片信息表,包括相片ID,相片存储链接,用户ID,相册ID。
名称 代码 数据类型 长度 注释
编号 id int(11) 11
相片存储链接 galleryurl varchar(255) 255
用户ID userid varchar(255) 255
相册ID galleryid varchar(255) 255
1.1.4.表images结构
明信片表,包括明信片ID,明信片存储路径,用户ID。
名称 代码 数据类型 长度 注释
编号 id int(11) 11
存储链接 posturl varchar(255) 255
用户ID userid varchar(255) 255
2.基于Android随心明信片系统实现
2.1.核心模块设计及实现
2.1.1.欢迎页面
系统首先加载欢迎页面,作为开屏页,该页面通过加载显示布局文件的全局背景,背景选取明信片风格的图片给人以亲切的感觉,加载图片后,通过decordView的postDelay方法,3秒后拉起登录界面,并结束欢迎页。
核心代码:
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splach);
getWindow().getDecorView().postDelayed(new Runnable() {
@Override
public void run() {
Intent intent = new Intent();
intent.setClass(getApplicationContext(), LoginActivity.class);
startActivity(intent);
finish();
}
}, 3000);
}
界面展示:
2.1.2.注册功能
注册功能需要录入用户名,密码。界面控件中,用到EditText、Button等。注册的布局文件中使用到了databinding技术,需要在布局文件的头部添加如下代码:
通过此方式可以导入UserBean的变量,在对应的用户名文本框和密码文本框中通过databinding的双向绑定技术实现编辑框中的内容自动设置到UserBean 对象中。下面以输入用户名为例,通过android:text="@={user.name}"实现双向绑定
界面展示:
点击立即注册按钮,将UserBean 的对象作为参数传递,通过JectPack里面的Room方式实现数据元素的插入操作。定义UserDao接口类,并通过@Insert注解的方式定义一个插入users表的接口。注册成功后,关闭注册界面,返回登录界面。
((MyApplication)getApplication()).getAppDatabase().userDao().inserUser(userBean);
@Dao
public interface UserDao {
@Insert
public void inserUser(UserBean user);
}
2.1.3.登录功能
用户注册成功后,或者已有账号进行登录的时候,点击登录按钮,会先去校验用户名编辑框或者密码编辑框中的内容是否为空, 如果为空则弹出Toast提示用户“用户名或密码不能为空”,均不为空则调用登录接口,查询users表中用户名和密码均满足条件的UserBean对象并返回查询结果,如果结果为空,说明没有满足条件的数据,登录失败,反之,弹出Toast表明登录成功,并跳转到主界面MainActivity。
@Query(“SELECt * FROM users WHERe name = :name AND password = :password”)
public UserBean login(String name, String password);
界面展示:
2.1.4.主界面展示
登录进入主界面后,可以清晰明了的看到本APP所划分的三大模块分别为:制作明信片,制作相册,个人管理。通过三个不同的Fragment实现点击下方导航栏后切换不同的Fragment,并对选中的按钮和文字进行高亮展示。
切换Fragment代码:
private FragmentTransaction switchFragment(Fragment targetFragment) {
FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction();
if (!targetFragment.isAdded()) {
if (currentFragment != null) {
transaction.hide(currentFragment);
}
transaction.add(R.id.frame_layout,targetFragment, targetFragment.getClass().getName());
} else {
transaction.hide(currentFragment).show(targetFragment);
}
currentFragment = targetFragment;
return transaction;
}
界面展示:
2.1.5.制作明信片
在制作明信片界面点击按钮“新建明信片”,会弹出单选对话框,让用户选择制作明信片的排版方式:
1)竖版;
当用户选择竖版模式,拉起VerticalActivity,弹出单选对话框,让用户选择插入明信片中的图片来源方式,是通过相机拍摄,还是通过相册导入。由于竖版布局和横版有差异,所以需要在Manifest.xml文件中对VerticalActivity进行方向的设置,将屏幕方向固定位竖屏android:screenOrientation=“portrait”。
2)横版;
横版模式与竖版类似,拉起HorizenActivity,也会让用户选择图片来源方式,不同之处在于固定的屏幕方向为横屏
android:screenOrientation=“landscape”
选择了不同的图片来源后,通过获取到的图片的URI,将图片展示出来,同时,填写邮编位置的文本编辑框均设置最大长度为1,确保每个方格中只能输入一个数字。
android:inputType=“number”
android:maxLength=“1”
信纸的横格纹实现效果通过自定义的EditText来实现的,通过计算控件高度,获取需要绘制的行数,在Ondraw函数中,遍历控件所需要绘制的行数,以点划线的方式绘制出每一行的横线。
protected void onDraw(Canvas canvas) {
//设置画笔
Paint mPaint = new Paint();
mPaint.setStyle(Paint.Style.STROKE);//描边
mPaint.setColor(Color.LTGRAY);//画笔颜色
PathEffect effects = new DashPathEffect(new float[]{5, 5, 5, 5}, 5);
mPaint.setPathEffect(effects);
int left = getLeft();//子View左边距离父view原点的距离
int right = getRight();//子View右边距离父view原点的距离
int paddingTop = getPaddingTop();//view的内容到view上面的距离
int paddingBottom = getPaddingBottom();//view的内容到view下面的距离
int paddingLeft = getPaddingLeft();//view的内容到view左边的距离
int paddingRight = getPaddingRight();//右边留白
int height = getHeight();//view高度
int lineHeight = getLineHeight();//返回一行的高度。注意标记内的文本可能高于或低于这个高度,布局可能包含额外的第一行或最后一行填充的部分。我们只是获取一行文字的高度,不计算间距。
int spcingHeight = (int) getLineSpacingExtra();//获取行距,就是每行文字距离上下横线的距离
int count = (height - paddingTop - paddingBottom) / lineHeight;//横线条数
for (int i = 0; i < count; i++) {
int baseline = lineHeight * (i + 1) + paddingTop - spcingHeight / 2;//得到第一行线,距离view上面的高度
canvas.drawLine(paddingLeft, (int) (baseline * 1.0), right - paddingRight * (int) 1.0, (int) (baseline * 1.0), mPaint);//划线
}
super.onDraw(canvas);
}
当长按图片后,可对明信片图片进行保存。实现方案为获取屏幕的截屏,为了提高用户体验,将该界面设置为全屏模式,防止在截屏时将状态栏和通知栏的信息保存进图片中。
public static Bitmap takeScreenShot(Activity pActivity) {
View view = pActivity.getWindow().getDecorView();
// 设置是否可以进行绘图缓存
view.setDrawingCacheEnabled(true);
// 如果绘图缓存无法,强制构建绘图缓存
view.buildDrawingCache();
// 返回这个缓存视图
Bitmap bitmap = view.getDrawingCache();
// 获取状态栏高度
Rect frame = new Rect();
// 测量屏幕宽和高
view.getWindowVisibleDisplayframe(frame);
int stautsHeight = frame.top;
Point point = new Point();
pActivity.getWindowManager().getDefaultDisplay().getSize(point);
int width = point.x ;
int height = point.y;
// 根据坐标点和需要的宽和高创建bitmap
bitmap = Bitmap.createBitmap(bitmap, 0, stautsHeight, width, height - stautsHeight);
return bitmap;
}
界面展示:
截图信息的保存方式为将图片保存到手机的外部存储路径中,在这之前需要先检查当前的应用是否获取读写外部存储的动态权限,只有允许授权后才可以正常保存图片,保存图片完成后需要将图片的存储路径以及对应的登录用户的ID信息插入进images数据表,实现一条明信片数据的插入。
明信片的分享方式是通过将截屏图片转换为Bitmap,将这条Bitmap数据插入到媒体数据库中,并返回对应的Uri,将该信息做为Intent中携带的参数,调用系统的分享函数Intent.createChooser,实现拉起不同应用的分享功能。
2.1.6.制作相册
切换至制作相册的Fragment后,界面会加载刷新当前用户所拥有的相册列表,通过调用如下的查询接口,实现从galleryname表中查询userid与当前登录的userid相同的所有相册对象。
@Query(“SELECt * FROM galleryname WHERe userid=:userid”)
public List loadAllDatas(int userid);
点击新建相册,弹出自定义的包含编辑框的提醒框,输入对应希望新建的相册名称后,点击确定按钮,通过如下接口实现向galleryname表中插入一条相册数据,随后刷新列表的显示。
@Insert
public void inserData(GalleryName data);
界面展示:
2.1.7.插入相册
单机相册列表中的某一项,可进入DIY相册界面,拉起GalleryActivity。
单击左上角的选择照片可以进行照片来源的选择,选中图片后居中将图片显示在当前界面。单击图片,界面下方会出现相框的选择栏,选中不同的元素,可以自定义设计不同的照片边框。长按后将装饰过的相册图片截屏并进行保存,确认保存时为了提升用户体验,先将左上角的添加按钮和文字进行隐藏,当截屏结束后再讲按钮和文字显示出来,截屏和保存的方法与明信片的方实现相同,具体实现参照上一小节的描述。保存图片时,需要将图片的存储路径,当前用户的userid,以及当前相册的galleryid都保存起来,插入到数据库中,方便后续查看相册功能,查找显示对应的用户以及对应的相册本中的照片。
核心代码
String saveUri = ScreenUtil.saveBmp(GalleryActivity.this);
if (!saveUri.equals("")){
GalleryBean bean = new GalleryBean();
bean.setGalleryid(galleryID);
bean.setGalleryurl(saveUri);
bean.setUserid(Const.userBean.getId());
MyApplication.myApplication.getAppDatabase().galleryDao().inserData(bean);
runonUiThread(new Runnable() {
@Override
public void run() {
addBtn.setVisibility(View.VISIBLE);
Toast.makeText(getApplicationContext(), "保存成功", Toast.LENGTH_SHORT).show();
}
});
}
界面展示:
2.1.8.个人管理
切换到个人管理界面后,展示在用户面前的是用户的个人基本信息,以及查看自己制作的明信片和相册的入口。点击我的明信片拉起PhotoGalleryActivity界面。该界面通过ViewPager来实现相册的动态滑动效果,刚进入界面的时候通过查询接口,获取userid相同的所有明显片图片的信息,将图片的存储地址获取到,展示ViewPager的每个item中。
核心代码
@Query(“SELECt * FROM images WHERe userid=:userid”)
public List loadAllDatas(int userid);
界面展示:
点击我的相册,拉起相册的列表信息界面,查询显示出userid为当前挡路用户的所有相册,选中某一相册,将相册的id传入Intent,拉起相册界面PhotoGalleryActivity,进入界面后通过查询接口获取uiserid,展示出所有该用户相册中的图片, 可左右滑动进行图片展示的切换效果,该效果通过保存一个ArrayList imageUrls,将搜索出来的所有满足条件的ImageBean的图片保存路径存入imageUrls里面,同时保存一个用来存储ImageView的列表List views=new ArrayList<>(),再新建一个自定的PageAdapter, 里面的数据列表就是这个views,将ViewPager设置该Adapter,实现绑定效果。
@Query(“SELECt * FROM images WHERe userid=:userid”)
public List loadAllDatas(int userid);
class MyAdapter extends PagerAdapter {
@Override
public int getCount() {
return views.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view==object;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
View v=views.get(position);
container.addView(v);
return v;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
View v=views.get(position);
//前一张图片划过后删除该View
container.removeView(v);
}
}
界面展示:



