您的位置:首页 > 移动开发

第一份功能较多的安卓项目--纪念日app

2016-06-01 08:10 246 查看
因为正值跟女朋友在一起的半周年。所以想着做个她需要的app给她用。其实网上同样功能的app很多,但都有广告,而且比较庞大,她的手机又比较老卡,所以就根据她的需求来写,哈哈,算是我的第一个项目经理吧。

首先说一下她的需求:

倒数日的功能,能够显示某个日子离现在还有几天,提供自动排序的功能

纪念日的功能,能够显示某个日子已经过去了几天,提供两种显示方法,日跟月。

手电筒的功能

备注功能。即倒数日中能够添加备注(未实现)

接下来就说一下实现的过程:

首先是设计界面,先做好下xml,经验表明,边写功能边敲代码绝对是不对的,因为会很乱。设想有一个登陆界面,界面上是头像,有圆角的输入框(自定义),有圆角的按钮

pw_shape.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"
android:padding="10dp">
<!--solid表示填充颜色,如果想让输入框看起来像透明的一样就让color跟背景颜色一样即可-->
<solid
android:color="#FFFFFF"></solid>
<!--corners表示四个角的弧度,注意bottomRightRadius是左下角,left是右下角的弧度-->
<corners
android:bottomRightRadius="15dp"
android:bottomLeftRadius="15dp"
android:topLeftRadius="15dp"
android:topRightRadius="15dp" />
<!--stroke表示描边,width表示宽度,color为描边的颜色-->
<stroke
android:width="2dp"
android:color="#FF99CC"/>
<!--padding:距离边缘的距离-->
<padding
android:left="10dp"/>
</shape>


手电筒在登陆界面。手电筒的代码其实挺简单的。主要就是打开闪光灯。代码如下

lightBtn.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v){
if(!flag){
layout.setBackgroundColor(Color.parseColor("#292421"));
lightBtn.setBackgroundResource(R.drawable.flash_head);
Camera camera = Camera.open();
parameters = camera.getParameters();
parameters.setFlashMode(Parameters.FLASH_MODE_TORCH);// 开启
camera.setParameters(parameters);
camera.startPreview();
flag=true;
}else{
flag=false;
layout.setBackgroundColor(Color.parseColor("#FFFFFF"));
lightBtn.setBackgroundResource(R.drawable.log_in_head_2);
parameters.setFlashMode(Parameters.FLASH_MODE_OFF);// 关闭
camera.setParameters(parameters);
camera.stopPreview();
camera.release();
camera=null;
}
}
});


开启的逻辑:

Camera camera = Camera.open();//打开Camera
Parameters parameters = camera.getParameters(); //获得参数          parameters.setFlashMode(Parameters.FLASH_MODE_TORCH);// 将闪光灯的模式设为开启
camera.setParameters(parameters);
camera.startPreview(); //开启闪关灯


关闭的逻辑:

layout.setBackgroundColor(Color.parseColor("#FFFFFF"));
lightBtn.setBackgroundResource(R.drawable.log_in_head_2);
parameters.setFlashMode(Parameters.FLASH_MODE_OFF);// 关闭
camera.setParameters(parameters);
camera.stopPreview();
camera.release();
camera=null;//*


这里同上,只需要将parameter设为off,再stopPreview,再release即可。要注意的一点便是:release后要将camera设为null,否则关了再开会报错,提示camera已经被使用

之后便什么新东西,添加Button,EditText等。

然后便是纪念日的设计,同样先设计xml。因为女票要求简单,只需要界面简洁,所以就上方自己设计的普通的菜单,下面是个自定义的listView

自己定制的菜单:

其实就是一层layout。然后在里面放自己需要的东西。那我们一般的都是上面一横条,横条中间是标题,两边是按钮,新建一个LinearLayout。一次放入Button,TextView,Button.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/date"
>

<Button
android:id="@+id/title_btn_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="返回"
android:textColor="#fff"/>
<!--要将TextView置中,则要将layout_width置0,layout_weight="1",这样会将一行分为两半,其中TextView占一半,另外两个button各占1/4-->
<TextView
android:id="@+id/title_text"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:gravity="center"
android:text="纪念日"
android:textColor="#fff"
android:textSize="24sp" />

<Button
android:id="@+id/title_btn_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="新建"
android:textColor="#fff"/>

</LinearLayout>


这个xml有两点要注意的,就是android:layout_gravity跟android:gravity的区别。

android:gravity是文字在控件中的对齐方式,而android:layout_gravity是控件在layout中的对齐方式。因为我们这个layout的高度设为wrap_content了,所以就只有按钮的高度。之后这个xml就可以被其他引用了。只需要将其他layout的标题栏隐藏,然后在xml中引入即可。隐藏标题栏的代码:

super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);//这一句一定要在setContentView前
setContentView(R.layout.activity_count_down);


然后便是listview的设计。因为我是想着左边一个纪念日的内容,然后右边一个框里面有天数,框的左边有”已经“二字,所以定制list_item.xml

首先将layout的orientation设为”horizontal”

然后将显示内容的TextView设为android:layout_weight=”1”。这样显示出来的效果就是“已经”二字贴着右边的框。

然后右边的框因为系统没有所以我们需要自己定制,其实也简单,就是一层有背景的layout,然后里面有一个TextView,设置其layout_gravity为center将其放在中间就可以了。

接着便是添加逻辑,主要是点击所在行可以进行编辑,长按弹出菜单可以删除,摇一摇可以让框3D旋转。

Adapter的重写,需要注意要把框所在的layout也申请个空间,因为字体是在这层layout上更改的。

class ViewHolder {
private LinearLayout countDownLayout;
private TextView content;
private TextView date;
}

private DayAdapter(Context context, ArrayList<Day1> dates) {
this.context = context;
this.dates = dates;
}

@Override
public int getCount() {
// TODO Auto-generated method stub
return dates.size();
}

@Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return dates.get(arg0);
}

@Override
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return arg0;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub

ViewHolder vh;
View view;

if (convertView == null) {
vh = new ViewHolder();
/**
*注意这里要先inflate自定义的list_item
*/
view = LayoutInflater.from(context).inflate(R.layout.list_item, null);
/**
*注意这里要给layout一个空间
*/
vh.countDownLayout = (LinearLayout) view.findViewById(R.id.count_down_layout);
vh.content = (TextView) view.findViewById(R.id.count_down_content);
vh.date = (TextView) view.findViewById(R.id.count_down_datetext);
view.setTag(vh);
} else {
view = convertView;
vh = (ViewHolder) view.getTag();
}
vh.content.setText(dates.get(position).content);
int passed = dates.get(position).days;
if (first){
vh.date.setText(passed + "天");
first=false;
}
else {
if (mark == 1) {
applyRotation(vh.countDownLayout, 0, 90);
vh.date.setText(passed + "天");
} else {
applyRotation(vh.countDownLayout, 0, 90);
vh.date.setText(passed + "月");
}
}
return view;
}

}


3D翻转特效:这个不懂,网上找的代码,需要翻转时调用applyRotation(layout,start,end)即可。一般把start设为0,end设为90,因为我们要翻转的是整个框,所以layout传入countDownLayout。因为我这个dayadapter中的list的泛型是Day1,其中有int型的一个数字,就是显示出来的天数。这样设计是为了能够让摇一摇时getView得以被调用(list中内容有变化,使用notifyDataSetChanged()才有效。)

private void applyRotation(LinearLayout layout, float start, float end) {
final float centerX = layout.getWidth() / 2.0f;
final float centerY = layout.getHeight() / 2.0f;
final Rotate3dAnimation rotation = new Rotate3dAnimation(start, end, centerX, centerY, 310.f, true);
rotation.setDuration(500);
rotation.setFillAfter(true);
rotation.setInterpolator(new AccelerateInterpolator());

rotation.setAnimationListener(new DisplayNextView(layout));

layout.startAnimation(rotation);
}

private final class DisplayNextView implements Animation.AnimationListener {
private LinearLayout layout;

DisplayNextView(LinearLayout layout) {
this.layout = layout;
}

public void onAnimationStart(Animation animation) {

}

public void onAnimationRepeat(Animation animation) {

}

@Override
public void onAnimationEnd(Animation arg0) {
// TODO Auto-generated method stub
layout.post(new SnapViews(layout));
}
}

private final class SnapViews implements Runnable {
private LinearLayout layout;

SnapViews(LinearLayout layout) {
this.layout = layout;
}

public void run() {
final float centerX = layout.getWidth() / 2.0f;
final float centerY = layout.getHeight() / 2.0f;
Rotate3dAnimation rotation = null;

layout.requestFocus();
rotation = new Rotate3dAnimation(90, 0, centerX, centerY, 310.0f, false);
rotation.setDuration(500);
rotation.setInterpolator(new DecelerateInterpolator());
layout.startAnimation(rotation);
}
}
}


之后是摇一摇。就是微信摇一摇的原理。使用手机的加速度传感器来感应是否有摇动。

private SensorManager sensorManager;
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
Sensor sensor =sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
sensorManager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_NORMAL);
/**
*在onSensorChanged中添加代码逻辑,我设置两次摇一摇的时间不能超过4秒
*/
private SensorEventListener listener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
float x = Math.abs(event.values[0]);
float y = Math.abs(event.values[1]);
float z = Math.abs(event.values[2]);
if ((System.currentTimeMillis() - CountDownActivity.currentTime > 4000) && (x > 12 || y > 12 || z > 12)) {
CountDownActivity.currentTime = System.currentTimeMillis();
if (mark == 1) {
mark = 2;
for (Day1 d : dayLists) {
d.days = countDay(d.date, mark);
adapter.notifyDataSetChanged();
}
} else if (mark == 2) {
mark = 1;
for (Day1 d : dayLists) {
d.days = countDay(d.date, mark);
}
adapter.notifyDataSetChanged();
}
}
}

@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {

}
};


弹出菜单:首先给菜单注册,然后重写代码即可。add方法的四个参数含义:

menu.add(groupId, itemId, order, title)

groupld 这个菜单的组别

itemid 是用来获取这个指定菜单项的.可以定义常量,不容易混,比如final int DELETE=1;

所谓order就是这个组别的第几项,0为第一项

title 不用说都知道是显示的标题了

registerForContextMenu(list);
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
menu.add(0, 1, 0, "删除");
}

@Override
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()) {
case 1:
Day1 d = (Day1) adapter.getItem(clickId);
Log.e("clickId", " " + clickId);
String content = d.content;
for (Day1 d1 : dayLists) {
if (d1.content.equals(content)) {
dayLists.remove(d1);
break;
}
}
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.delete("CountDays", "content=?", new String[] { d.content });
adapter.notifyDataSetChanged();
}
return true;
}


至于添加详情的代码则没什么好写的了。界面也没有设计。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: