美文网首页程序员Android优秀开源优秀案例
Android:Moring-早安闹钟开发过程记录(四)

Android:Moring-早安闹钟开发过程记录(四)

作者: 黑丫山上小旋风 | 来源:发表于2016-01-19 14:58 被阅读349次

    FragmentMenu侧滑菜单界面实现

    1.界面实现

    侧滑菜单.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(200);
    

    侧滑菜单就可以愉快的开始工作了

    2.功能实现

    天气和震动比较简单,用SP记录一下用户的选择就OK了
    比较复杂的是更换城市和音量改变

    • 更换城市


      changecity.jpg
      • 在用户输入的时候给用户动态提示
        • 配置数据库
          首先配置好数据库,在第一次启动应用的时候将数据库拷贝到本地
    in=getResources().getAssets().open(dbName);
    out=new FileOutputStream(file);
    byte[] buffer=new byte[1024];
    int len=0;
    while((len=in.read(buffer))!=-1){
              out.write(buffer, 0, 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() > 0) {
                  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 > 4) {
              params.height = 500;
    } 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(1f, 1f);
                      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)/100;
              mAudioManager.setStreamVolume(AudioManager.STREAM_ALARM, setVolume, 0);
    }
    

    setStreamVolume()中的第二个参数的解释是传入音量的绝对值,我的理解是音量绝对值可能不一定是百分数,所以先获取到手机的最大音量值,然后通过百分比计算应该传入的绝对值(一定要先乘再除啊,否则int类型你懂得,误差会比较大),具体绝对值是什么我也没去研究,不过这样做应该没有太大的问题。
    获取和修改系统音量需要用到的权限

    <uses-permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    
    写到这儿,这个项目基本上比较重要的地方都总结完了,另外为了防止应用被无情的杀死,我翻看了很多大神的博客,目前比较有效的应该是开启一个独立进程相互监视,互相扶持~,后面有空的话再补一篇吧!

    完结!

    相关文章

      网友评论

        本文标题:Android:Moring-早安闹钟开发过程记录(四)

        本文链接:https://www.haomeiwen.com/subject/bigkkttx.html