Android学习之——APP番茄工作法——小结(1)

2014-4-3补:
最近一直忘记回复:给位需要源码的,请到这里https://github.com/MrFuFuFu/TomatoTask  版本已经更新为1.0.1,且已在豌豆荚,应用宝,360手机助手,百度应用,应用汇等市场上架了,欢迎大家的下载。源码写的有点混乱。如果有问题,还望回复告知,会及时修改的。

注:需要引用问题一中的library, 这个library除了去github下载也可以戳这里:http://download.csdn.net/detail/fu222cs98/7026253
       是不是应该加个开源协议,我看他们都这么写:http://www.apache.org/licenses/LICENSE-2.0
再注:或者我觉得这个开源协议比较好玩:http://zh.wikipedia.org/wiki/WTFPL

今天,我的第一个APP:番茄工作法 1.0版本终于终于终于完成了,虽然还有很多很多的不足之处,但是,终归算是告一个段落了。
第一款小应用,其中的艰辛冷暖自知,各种摸爬滚打,各种度娘谷歌。
简单讲解下其中碰到的问题:
问题一:android.support.v4.app.Fragment 包下没有PreferenceFragment的问题。
起初做的设置界面太过难看,所以打算使用谷歌力推的碎片机制,但是发现v4包下面居然没有PreferenceFragment类。然后各种搞不定。
最后在谷歌的帮助下顺利找到实现方法(花了我将近一个礼拜的时间,泪奔,新手不解释...)
https://github.com/kolavar/android-support-v4-preferencefragment
进入上面的链接下载这个library。
实现方式和android.preference.PreferenceFragment 下的方式一样,具体代码如下:
public class fragment3 extends PreferenceFragment{
    public static fragment3 newInstance(Bundle bundle) {
        fragment3 frag = new fragment3();
        frag.setArguments(bundle);
        return frag;
    }
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preferences);  
        Log.v("huahua", "fragment3-->onCreate()");
    }
}
具体代码我会在下面全部放出来
其中有一点不足,相当遗憾:preferences.xml中的RingtonePrefere nce设置铃声的数据一直无法保存到SharedPreferences中去,导致无法设定铃声。如果有大神能够解决  感激不敬。
  Android学习之——APP番茄工作法——小结(1)_第1张图片 Android学习之——APP番茄工作法——小结(1)_第2张图片

注意在preferences.xml中最好不要设定自定义的View,因为这个问题困扰了我很久。
关于PreferenceFragment的其他用法: http://www.oschina.net/question/565065_107985
由于PreferenceFragment中没有SeekBar 重写SeekBar的方式介绍: http://www.eoeandroid.com/thread-115052-1-1.html

问题二:保存简单数据的问题
在应用中可能需要保存一些很简单的数据,如界面上显示一个执行任务的次数等,这些简单数据可以放到 SharedPreferences,它会将数据保存到一个xml中去,具体的使用代码如下:
SharedPreferences mySharedPreferences = getActivity().getSharedPreferences("TomatoCount",
        Activity.MODE_PRIVATE);//获取SharedPreferences 中的值,TomatoCount表示保存的文件名称
String dateStr = mySharedPreferences.getString("date", "2001-01-01");//获取字符串
todayTomatoCount = mySharedPreferences.getInt("todayTomatoCount", 0);//获取存储的今日番茄时间,获取int型数据,如果不存在默认设置为0
allTomatoCount = mySharedPreferences.getInt("allTomatoCount", 0);//获取存储的合计番茄时间
String dateNowString = (new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())).format(new java.util.Date());
if (!dateStr.equals(dateNowString)) {//判断存储时间是否和当前时间在同一天
    todayTomatoCount=0;
    SharedPreferences.Editor editor = mySharedPreferences.edit();
    editor.putInt("todayTomatoCount", todayTomatoCount);//写入数据到Editor 其中第一个参数是字段的名称,第二个参数是字段的值,该写入的是int类型
    editor.commit();//提交,写入到xml文件中
}

问题三:修改字体
在assets文件夹下新建fonts文件夹,将需要的字体(*.ttf)放入到该文件夹下,代码中使用该字体的方法如下:
//修改字体
Typeface fontFace = Typeface.createFromAsset(getActivity().getAssets(), "fonts/Roboto-Thin.ttf");
tomatoTxtView.setTypeface(fontFace);

问题四:如何在PreferenceFragment实现类中如果要实时的获取修改的值等
如果当ListPreference中的值改变以后,我要在ListPreference的副标题中显示改变的值该如何操作呢:重写onSharedPreferenceChanged方法
如果当我们需要点击preference进入到另外一个页面时,或者我们需要跳转到网页时,该如何操作呢:重写onPreferenceTreeClick方法
public class SettingPreferenceFragment extends PreferenceFragment implements OnSharedPreferenceChangeListener {
    ListPreference lstPre_TomatoTime_value, lstPre_BreakTime_value;
    public SettingPreferenceFragment() {
        // TODO 自动生成的构造函数存根
    }
    @Override
    public void onCreate(Bundle paramBundle) {
        // TODO 自动生成的方法存根
        super.onCreate(paramBundle);
        addPreferencesFromResource(R.xml.preferences);
        SharedPreferences prefs=PreferenceManager.getDefaultSharedPreferences(getActivity());
        prefs.registerOnSharedPreferenceChangeListener(this);
        lstPre_TomatoTime_value=(ListPreference)findPreference("TomatoTime_value");
        lstPre_BreakTime_value=(ListPreference)findPreference("BreakTime_value");
        lstPre_TomatoTime_value.setSummary(lstPre_TomatoTime_value.getEntry());
        lstPre_BreakTime_value.setSummary(lstPre_BreakTime_value.getEntry());
    }
    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
            String key) {
        // TODO 自动生成的方法存根
        if (key.equals("TomatoTime_value")) {
            lstPre_TomatoTime_value.setSummary(lstPre_TomatoTime_value.getEntry());
        }
        if (key.equals("BreakTime_value")) {
            lstPre_BreakTime_value.setSummary(lstPre_BreakTime_value.getEntry());
        }
    }
     
    @Override
    public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
            Preference preference) {
        // TODO 自动生成的方法存根
        if (preference.getKey().equals("clearCount")) {
            alertDialogShow();
        }
        if (preference.getKey().equals("aboutTomatoTask")) {
            Uri uri = Uri.parse("http://baike.baidu.com/link?url=b7rlhS6YssFup2xqAjnw9__6VsQnyhtVT8Gx_-qwckUE4IZ-ns6i_jw9w_aKH-C_sjWheb9NFR_GZcfUII0bV_");
            startActivity(new Intent(Intent.ACTION_VIEW,uri));
        }
        return false;
    }
     
    /**
     * 显示AlertDialog
     */
    private void alertDialogShow() {
        new AlertDialog.Builder(getActivity()).setTitle("清除?").setMessage("是否清除计数?\n注:该操作不可逆!").setPositiveButton("清除", new DialogInterface.OnClickListener() {
             
            @Override
            public void onClick(DialogInterface dialog, int which) {
                // TODO 自动生成的方法存根
                SharedPreferences mySharedPreferences = getActivity().getSharedPreferences("TomatoCount",
                        Activity.MODE_PRIVATE);
                SharedPreferences.Editor editor = mySharedPreferences.edit();
                editor.putInt("todayTomatoCount", 0);
                editor.putInt("allTomatoCount", 0);
                editor.commit();
                Toast.makeText(getActivity(), "清除成功!", Toast.LENGTH_SHORT).show();
            }
        }).setNegativeButton("取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                // TODO 自动生成的方法存根
            }
        }).create().show();
    }
}

问题五:如何实现倒计时

在android 已经给我们封装好了一个倒计时的类,我们直接拿来实现就可以啦,具体过程如下:
private TimeCount time;
2. new 一个TimeCount, timeSpan是需要倒计时的时间(毫秒),1000是倒计时间隔,这里是一秒
time = new TimeCount(timeSpan, 1000);// 构造CountDownTimer对象
time.start();
3. 写内部类TimeCount 继承自CountDownTimer 其中onTick表示,在上述设定的倒计时间隔期间做什么,onFinish表示计时完毕时做什么
class TimeCount extends CountDownTimer {
    public TimeCount(long millisInFuture, long countDownInterval) {
        super(millisInFuture, countDownInterval);// 参数依次为总时长,和计时的时间间隔
    }
    /**
     * 计时过程显示
     */
    @Override
    public void onTick(long millisUntilFinished) {
        // TODO 自动生成的方法存根
    }
    /**
     * 计时完毕时触发
     */
    @Override
    public void onFinish() {
        // TODO 自动生成的方法存根
    }
}

问题六:触发点击事件:当我们点击返回按键时,是否弹出AlertDialog提示框,或者是提示“再按一次退出”的实现:

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (flag == 2) {
        if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
            AlertDialog.Builder alertBuilder = new AlertDialog.Builder(
                    MainActivity.this);
            alertBuilder
                    .setTitle("放弃?")
                    .setMessage("是否放弃这个番茄并退出吗?")
                    .setPositiveButton("确定",
                            new DialogInterface.OnClickListener() {
 
                                @Override
                                public void onClick(DialogInterface dialog,
                                        int which) {
                                    // TODO 自动生成的方法存根
                                    time.cancel();
                                    MainActivity.this.finish();
                                }
                            })
                    .setNegativeButton("取消",
                            new DialogInterface.OnClickListener() {
 
                                @Override
                                public void onClick(DialogInterface dialog,
                                        int which) {
                                    // TODO 自动生成的方法存根
                                    dialog.cancel();
                                }
                            }).create();
            alertBuilder.show();
        }
    } else {
        if (keyCode == KeyEvent.KEYCODE_BACK
                && event.getAction() == KeyEvent.ACTION_DOWN) {
            if ((System.currentTimeMillis() - exitTime) > 2000) {
                Toast.makeText(getApplicationContext(), "再按一次退到主界面",
                        Toast.LENGTH_SHORT).show();
                exitTime = System.currentTimeMillis();
            } else {
                time.cancel();
                finish();
                System.exit(0);
            }
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }
    return true;
}

问题七:震动的实现

private Vibrator vibrator;
//开启震动
vibrator =(Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
long [] pattern = {200,500,200,500,1200,500,200,500};   // 停止 开启 停止 开启  
vibrator.vibrate(pattern,-1);           //重复两次上面的pattern 如果只想震动一次,index设为-1 

问题八:重写ProgressBar,设置为圆形进度条:

来源:http://www.pocketdigi.com/20130712/1136.html

package com.android.tomatotask;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
public class CircleProgressBar extends View {
    private int maxProgress = 10;//最大进度
    private int progress = 0;//当前进度
    private int progressStrokeWidth = 6;//线宽
    // 画圆所在的矩形区域
    RectF oval;
    Paint paint;
    public CircleProgressBar(Context context) {
        super(context);
        // TODO 自动生成的构造函数存根
    }
    public CircleProgressBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO 自动生成的构造函数存根
        oval = new RectF();
        paint = new Paint();
    }
    public CircleProgressBar(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        // TODO 自动生成的构造函数存根
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);   
        /**
         * 画最外层的大圆环
         */
        int centre = getWidth()/2; //获取圆心的x坐标
        int radius = (int) (centre - progressStrokeWidth/2); //圆环的半径
        paint.setColor(Color.WHITE);//(roundColor); //设置圆环的颜色
        paint.setStyle(Paint.Style.STROKE); //设置空心
        paint.setStrokeWidth(progressStrokeWidth); //设置圆环的宽度
        paint.setAntiAlias(true);  //消除锯齿 
        canvas.drawCircle(centre, centre, radius, paint); //画出圆环        
        /**
         * 画圆弧 ,画圆环的进度
         */       
        //设置进度是实心还是空心
        paint.setStrokeWidth(progressStrokeWidth); //设置圆环的宽度
        paint.setColor(Color.rgb(0x57, 0x87, 0xb6));  //设置进度的颜色 
        RectF oval = new RectF(centre - radius, centre - radius, centre
                + radius, centre + radius);  //用于定义的圆弧的形状和大小的界限
            paint.setStyle(Paint.Style.STROKE);
            canvas.drawArc(oval, -90, 360 * progress / maxProgress, false, paint);  //根据进度画圆弧  绘制白色圆圈,即进度条背景
    }   
    public int getMaxProgress(){
        return maxProgress;
    }   
    public void setMaxProgress(int maxProgress){
        this.maxProgress = maxProgress;
    }   
    public void setProgress(int progress){
        this.progress = progress;
        this.invalidate();
    }   
    public void setProgressNotInUiThread(int progress){
        this.progress = progress;
        this.postInvalidate();
    }
}
相关XML使用书写方式:


问题九:Animation动画效果的实现

protected Animation animation;
// 动画资源文件
ID = new int[] { R.anim.my_alpha_action, R.anim.my_scale_action,
        R.anim.my_rotate_action, R.anim.alpha_scale,
        R.anim.alpha_rotate, R.anim.scale_rotate,
        R.anim.alpha_scale_rotate, R.anim.myown_design };
animation = AnimationUtils.loadAnimation(MainActivity.this,
        ID[randow]);//randow为随机取到0~7的数的随机数
textView.startAnimation(animation);

问题十:针对只有几个确定的数,使用 SeekBar

打个比方,我只有10, 20, 30, 40, 50这几个数,我想使用SeekBar,最小值是10,最大值是50,如果我拖动进度条到95%的时候,刻度自动进到100% 即值为50的情况,那么在这种情况下我们该如何处理呢
请看下面的代码:
private class SeekBarListener implements SeekBar.OnSeekBarChangeListener {
    private TextView textView;
    private int TickStep;
    private int StartTick;
    public SeekBarListener(TextView tv, int startTick, int tickStep) {
        textView = tv;
        TickStep = tickStep;
        StartTick = startTick;
    }
    @Override
    public void onProgressChanged(SeekBar seekBar, int progress,
            boolean fromUser) {
        // TODO Auto-generated method stub
        if (fromUser) {
            // ..
        }
        // 时间=process*步长+初始值
        // int progress=seekBar.getProgress();
        int curTick = progress + StartTick;
        int remainder = curTick % TickStep;
        int halfStep = TickStep % 2 == 0 ? TickStep - TickStep % 2
                : TickStep - TickStep % 2 + 1;
        if (remainder < halfStep) {
            curTick -= remainder;
        } else {
            curTick += (TickStep - remainder);
        }
        // seekBar.setProgress(curTick - StartTick);
        textView.setText(curTick + "min");
    }
    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {
        // TODO Auto-generated method stub
    }
    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
        // TODO Auto-generated method stub
        // 时间=process*步长+初始值
        int progress = seekBar.getProgress();
        int curTick = progress + StartTick;
        int remainder = curTick % TickStep;
        int halfStep = TickStep % 2 == 0 ? TickStep - TickStep % 2
                : TickStep - TickStep % 2 + 1;
        if (remainder < halfStep) {
            curTick -= remainder;
        } else {
            curTick += (TickStep - remainder);
        }
        seekBar.setProgress(curTick - StartTick);
        textView.setText(curTick + "min");
    }
}





问题一的相关代码下载:http://download.csdn.net/detail/fu222cs98/7026253

番茄工作法APK下载:http://www.wandoujia.com/apps/com.android.tomatotask 注:源代码已分享在GitHub上

效果图浏览请戳:
Android学习之——APP番茄工作法——小结(2): http://blog.csdn.net/fu222cs98/article/details/21056435







你可能感兴趣的:(Android)