今天,我的第一個APP:番茄工作法 1.0版本終於終於終於完成了,雖然還有很多很多的不足之處,但是,終歸算是告一個段落了。第一款小應用,其中的艱辛冷暖自知,各種摸爬滾打,各種度娘Google。簡單講解下其中碰到的問題:
問題一:android.support.v4.app.Fragment 包下沒有PreferenceFragment的問題。起初做的設定介面太過難看,所以打算使用Google力推的片段機制,但是發現v4包下面居然沒有PreferenceFragment類。然後各種搞不定。最後在Google的協助下順利找到實現方法(花了我將近一個禮拜的時間,淚奔,新手不解釋...)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中的RingtonePreference設定鈴聲的資料一直無法儲存到SharedPreferences中去,導致無法設定鈴聲。如果有大神能夠解決 感激不敬。
注意在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型資料,如果不存在預設設定為0allTomatoCount = 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提示框,或者是提示“再按一次退出”的實現:
@Overridepublic 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使用書寫方式:
<com.android.tomatotask.CircleProgressBar android:id="@+id/circleProgressbar" android:layout_width="300dp" android:layout_height="300dp" android:layout_centerInParent="true" /><android.support.v4.view.ViewPager android:id="@+id/viewpage" android:layout_width="match_parent" android:layout_height="match_parent" />
問題九: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://pan.baidu.com/s/1jGC4fXG 註:原始碼已分享在GitHub上
Android學習之——APP番茄工作法——小結(2):http://blog.csdn.net/fu222cs98/article/details/21056435