天天看點

Android:Moring-早安鬧鐘開發過程記錄(四) FragmentMenu側滑菜單界面實作

FragmentMenu側滑菜單界面實作

1.界面實作

Android:Moring-早安鬧鐘開發過程記錄(四) FragmentMenu側滑菜單界面實作

側滑菜單.jpg

  • 界面顯示比較簡單,因為用的SlidingMenu的第三方庫是以實作起來比較簡單

    github位址:https://github.com/jfeinstein10/SlidingMenu

    -在建立一個側滑菜單的布局檔案,布局寫成什麼樣菜單就長什麼樣

    顯示菜單的Activity需要繼承SlidingFragmentActivity

    setBehindContentView(R.layout.menu_home);
    //擷取到slidingMenu對象SlidingMenu slidingMenu = getSlidingMenu();
    slidingMenu.setMode(SlidingMenu.RIGHT);//設定菜單在哪一邊
    slidingMenu.setShadowWidthRes(R.dimen.shadow_width);
    //設定陰影圖檔
    slidingMenu.setShadowDrawable(R.drawable.shadow);
    //設定為全屏拉出菜單
    slidingMenu.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);
    //設定菜單寬度
    slidingMenu.setBehindOffset();                
    側滑菜單就可以愉快的開始工作了

2.功能實作

天氣和震動比較簡單,用SP記錄一下使用者的選擇就OK了

比較複雜的是更換城市和音量改變

  • 更換城市
    Android:Moring-早安鬧鐘開發過程記錄(四) FragmentMenu側滑菜單界面實作
    changecity.jpg
    • 在使用者輸入的時候給使用者動态提示
      • 配置資料庫

        首先配置好資料庫,在第一次啟動應用的時候将資料庫拷貝到本地

        in=getResources().getAssets().open(dbName);
        out=new FileOutputStream(file);
        byte[] buffer=new byte[];
        int len=;
        while((len=in.read(buffer))!=-){
            out.write(buffer, , len);
        }
                   
        定義一個工具類進行查找資料庫,這裡需要進行模糊查找

        "select 字段名 from 表名 where 字段名like '%" + 使用者輸入的字元+ "%'"

        将包含該字元的資料全部找出,傳回String清單
        public ArrayList<String> find(String input){
            String path="data/data/com.joe.lazyalarm/files/china_Province_city_zone.db";
            SQLiteDatabase sql=SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READONLY);
            //模糊查詢
            ArrayList<String> cityList=new ArrayList<String>();
            Cursor cursor=sql.rawQuery("select CityName from T_City where CityName like '%" + input + "%'", null);
            while (cursor.moveToNext()){
                String cityName=cursor.getString(cursor.getColumnIndex("CityName"));
                cityList.add(cityName);
            }
            sql.close();
            cursor.close();
            return cityList;
        }                
      • 界面實作

        Android自己有一個控件叫AutoCompleteTextView-自動補全文本編輯框,用這個控件可以實作這個效果,與資料庫建立連接配接就可以了。

        我沒有用AutoCompleteTextView,而是自己實作這個效果。分析一下這個控件的效果不難得出就是一個EditText和一個ListView就可以實作

        • 布局檔案:
          <RelativeLayout 
          xmlns:android="http://schemas.android.com/apk/res/android"    
          android:layout_width="match_parent"    
          android:layout_height="match_parent"    >
            <EditText
                android:id="@id/et_change_city"
                android:hint="例如:重慶"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
            <ListView
                android:visibility="gone"
                android:layout_below="@id/et_change_city"
                android:id="@id/lv_change_city"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/>
          </RelativeLayout>
                     

          說明:我是通過setView()将布局添加到對話框中,為了省事并沒有讓ListView懸浮在對話框上面,如果需要懸浮的話改一下布局檔案就可以了

          因為ListView沒有懸浮,必然會占用dialog的寬高,是以在初始化的時候将ListView的狀态設定為gone,不設定也沒有關系,因為代碼中會設定輸入一個字元後才開啟提示

      • 代碼實作

        首先将布局塞給對話框

        dao = new CityDao();//資料庫讀取工具
        cityList = new ArrayList<String>();//查找到的城市清單
        final View autoLayout = View.inflate(mActivity, R.layout.auto_edit_view, null);
        final EditText autoText = (EditText) autoLayout.findViewById(R.id.et_change_city);
        ListView listHint = (ListView) autoLayout.findViewById(R.id.lv_change_city);
        builder.setView(autoLayout);
                   

        然後為ListView設定一個Adapter

        Adapter的getView()方法

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder;
            if(convertView==null){
                convertView=View.inflate(mActivity,R.layout.item_change_city,null);
                holder=new ViewHolder();
                holder.hint= (TextView) convertView.findViewById(R.id.tv_hint_city);
                convertView.setTag(holder);
            }else{
                holder= (ViewHolder) convertView.getTag();
            }
            holder.hint.setText(cityList.get(position));
            return convertView;
        }
                   

        擴充卡設定好了以後,就需要監聽文本框的輸入情況來動态改變ListView

        EditText有一個方法addTextChangedListener(TextWather tw);用于監聽文本框的文字改變,在onTextChanged中實作顯示提示

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            if (s.length() > ) {
                Log.d("changecity", "顯示listview");
                //如果字元大于0,顯示listview
                listHint.setVisibility(View.VISIBLE);
                cityList = dao.find(s.toString());
                adapter.notifyDataSetChanged();
            } else {
                listHint.setVisibility(View.GONE);
            }
        }                

        每當文字發生改變時擷取到使用者輸入的字元,查找資料庫更新cityList并重新整理UI。

        還有一個問題,由于每次查詢傳回的資料條數不一緻,導緻有時候資料條數太多ListView太長被鍵盤蓋住了。這裡還需要限制一下ListView的高度

        int itemCount=adapter.getCount()

        擷取到目前的資料條數,如果條數大于四條就将ListView限制死,如果小于四條就以ListView本身的高度為準,在onTextChanged中添加
        int itemCount = adapter.getCount();
        Log.d("changecity", "count" + itemCount);
        RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) listHint.getLayoutParams();
        if (itemCount > ) {
            params.height = ;
        } else {
            params.height = RelativeLayout.LayoutParams.WRAP_CONTENT;
        }
        listHint.setLayoutParams(params);
                   

        最後一步,監聽ListView的Item點選事件,實作使用者點選提示補全編輯框

        點選後提示消失

        listHint.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                TextView cityName= (TextView) view.findViewById(R.id.tv_hint_city);
                autoText.setText(cityName.getText());
                listHint.setVisibility(View.GONE);
            }
        });                
        大功告成!
  • 音量控制

    利用SeekBar來改變音量,首先在使用者滑動了SeekBar的時候要播放鈴聲(不然調屁的音量啊!)

    設定SeekBar的監聽,在onProgressChanged()中去實作邏輯

    setOnSeekBarChangeListener(OnSeekBarChangeListener listener);

    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
            playAlarmMusic();//播放音樂
            setSystemVolume(progress);//調節音量
            PrefUtils.putInt(mActivity, ConsUtils.ALARM_VOLUME, progress);//記錄音量
    }                
    現在依次來寫出這兩個方法吧,首先是播放音樂
    //播放音樂
        private void playAlarmMusic() {
            if(mPlayer==null){
                try {
                    mPlayer=new MediaPlayer();
                    AssetFileDescriptor assetFileDescriptor=mActivity.getAssets().openFd("everybody.mp3");
                    mPlayer.reset();
                    mPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
                    mPlayer.setDataSource(assetFileDescriptor.getFileDescriptor(), assetFileDescriptor.getStartOffset(), assetFileDescriptor.getLength());
                    mPlayer.setVolume(, );
                    mPlayer.prepare();
                    mPlayer.start();
                    isMusicOn=true;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }                

    必須将mPlayer的AudioStreamType設定為某一個類型,否則是沒有什麼卵用的,因為是鬧鐘是以就設定為STREAM_ALARM就好

    另外因為每次滑動都會調用該方法,是以先判斷一下目前是否已經在播放了,在播放了就不有再播放了。

    isMusicOn是做一個标記為後面關掉音樂用

    • AudioManager來設定音量

      AudioManager是系統服務通過getSystem(AUDIO_SERVICE)得到執行個體

      private void setSystemVolume(int progress) {
          //擷取到音量調節管理器
          int maxVolume= mAudioManager.getStreamMaxVolume(AudioManager.STREAM_ALARM);
          int setVolume=(maxVolume*progress)/;
          mAudioManager.setStreamVolume(AudioManager.STREAM_ALARM, setVolume, );
      }                

      setStreamVolume()中的第二個參數的解釋是傳入音量的絕對值,我的了解是音量絕對值可能不一定是百分數,是以先擷取到手機的最大音量值,然後通過百分比計算應該傳入的絕對值(一定要先乘再除啊,否則int類型你懂得,誤差會比較大),具體絕對值是什麼我也沒去研究,不過這樣做應該沒有太大的問題。

      擷取和修改系統音量需要用到的權限

      <uses-permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT" />
      <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
                 
      寫到這兒,這個項目基本上比較重要的地方都總結完了,另外為了防止應用被無情的殺死,我翻看了很多大神的部落格,目前比較有效的應該是開啟一個獨立程序互相監視,互相扶持~,後面有空的話再補一篇吧!

完結!