跳转后的homeActivity,要在背景上再显示功能图标,这又是一个view,而这个需要adapter去实现,详情看日志day5.15的介绍
homeactivity
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:layout_width="fill_parent" android:layout_height="60dp" android:text="功能列表" android:background="#00FF00" android:gravity="center" android:textSize="25sp"/> <GridView android:id="@+id/gv_home_nine" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center" android:numColumns="3"/> </LinearLayout>
item_home
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/iv_home_pic" android:src="@drawable/ic_launcher" android:layout_gravity="center" android:layout_margin="10dp"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/tv_home_name" android:layout_gravity="center_horizontal" android:text="功能"/> </LinearLayout>
activity,注意最后一个重载方法,用来显示view的
public class HomeActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.activity_home); GridView gv_home_nine = (GridView) findViewById(R.id.gv_home_nine); gv_home_nine.setAdapter(new MyListAdapter()); } class MyListAdapter extends BaseAdapter{ @Override public int getCount() { // TODO Auto-generated method stub return 9; } @Override public Object getItem(int position) { // TODO Auto-generated method stub return null; } @Override public long getItemId(int position) { // TODO Auto-generated method stub return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { // TODO Auto-generated method stub View view = View.inflate(HomeActivity.this, R.layout.item_home, null); return view; } } }
导入准备好的图片后,需要显示他们
希望能实现一个跑马灯效果,显示一些额外的信息,在activity_home里加上一个textView,这里用系统的控件不好实现,无法获得焦点,为了能够自动获得焦点,一进入这个activity就能显示出来,这就需要自定义控件,FocusTextView继承于textView,他要实现3个构造方法,最后调用一个方法来判断是否有焦点
import android.content.Context; import android.util.AttributeSet; import android.widget.TextView; public class FocusTextView extends TextView { public FocusTextView(Context context) { super(context); // TODO Auto-generated constructor stub } public FocusTextView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // TODO Auto-generated constructor stub } public FocusTextView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } //判断是否获得焦点 @Override public boolean isFocused() { // 返回true确保获得焦点 return true; } }
在layout里使用全面来调用
<com.rjl.mobilephonemanager.FocusTextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="您当前使用的是手机卫士2.0版本,当前最新版本是3.0版本,建议下载!" android:singleLine="true" android:textSize="14sp" android:ellipsize="marquee" android:focusable="true" android:clickable="true" />
OK,现在来实现具体功能块,首先完善之前的splash的更新功能,在设置里应该有一个是否自动更新的功能,单独需要一个settingActivity,首先记得manifest里声明下
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:layout_width="fill_parent" android:layout_height="60dp" android:text="设置中心" android:background="#00FF00" android:gravity="center" android:textSize="25sp" /> <RelativeLayout android:layout_width="fill_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/tv_setting_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="自动更新" android:layout_margin="5dp" android:textSize="20sp"/> <TextView android:id="@+id/tv_setting_description" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="自动更新开启" android:textSize="16sp" android:layout_marginLeft="5dp" android:layout_below="@+id/tv_setting_title"/> <CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true"/> </RelativeLayout> </LinearLayout>
实现点击的跳转,需要在homeactivity里实现MyOnItemClickListener
protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.activity_home); GridView gv_home_nine = (GridView) findViewById(R.id.gv_home_nine); gv_home_nine.setAdapter(new MyListAdapter()); gv_home_nine.setOnItemClickListener(new MyOnItemClickListener()); } class MyOnItemClickListener implements OnItemClickListener{ //注意position的值,在数组里是最后一个,8 @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // TODO Auto-generated method stub switch (position) { case 8: //跳入到setting页面 Intent intent = new Intent(HomeActivity.this,SettingActivity.class); startActivity(intent); break; default: break; } } }
此时再回过头想想,setting里会有多个打钩确认,如果都是这么写就繁琐了,所以可以抽出来,通过自定义组合控件来实现,settingItem,继承于relativeLayout,同样有3个构造方法
前面有一个自定义控件了,应该建一个专用的包存这一类控件
import android.content.Context; import android.util.AttributeSet; import android.widget.RelativeLayout; public class SettingItem extends RelativeLayout { public SettingItem(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // TODO Auto-generated constructor stub } public SettingItem(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } public SettingItem(Context context) { super(context); // TODO Auto-generated constructor stub } }
在这三个方法里都应该初始化,需要一个方法init()
public class SettingItem extends RelativeLayout { public SettingItem(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // TODO Auto-generated constructor stub init(); } public SettingItem(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub init(); } public SettingItem(Context context) { super(context); // TODO Auto-generated constructor stub init(); } //初始化,三个构造函数都需要调用它 //通过这个初始化,通过填充器将三个控件填充到这个view,再将view加入到组合控件里 //在activity_setting里组合,另需一个setting_item来实现原来的三个控件 private void init() { // TODO Auto-generated method stub View view= View.inflate(getContext(), R.layout.setting_item, null); //将控件的view加载到这个view上 this.addView(view); } }
原来的layout里就只需要一个组合控件,但是还是要一个layout去实现组合控件里的三个控件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:layout_width="fill_parent" android:layout_height="60dp" android:text="设置中心" android:background="#00FF00" android:gravity="center" android:textSize="25sp" /> <com.rjl.mobilephonemanager.ui.SettingItem android:layout_width="fill_parent" android:layout_height="wrap_content"/> </LinearLayout>
新建一个layout setting_item,原有的三个控件弄进来
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" > <TextView android:id="@+id/tv_setting_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="自动更新" android:layout_margin="5dp" android:textSize="20sp"/> <TextView android:id="@+id/tv_setting_description" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="自动更新开启" android:textSize="16sp" android:layout_marginLeft="5dp" android:layout_below="@id/tv_setting_title"/> <CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true"/> </RelativeLayout>
这中间有一个问题困扰了好久,UNbound prefix,老师在的完整代码里有一个额外的前缀,后续要用到,但是目前没有,我一股脑复制进来,导致XML解析错误,更进步导致无法通过R.layout找到view,去掉那一段就好了
组合控件还有另一个实现方式,注意init(0的第三个参数,ViewGroup型的root或者是parent,因为这个组合控件的view实际上是挂在RelativeLayout上,所以第三个参数传递一个this指向他,就相当于第一种方式的addView了
至此自定义组合控件解决了,接下来实现功能,勾选上就能自动更新
点击事件,给activity_setting里的组合控件加一个ID,oncreate里调用,他是一个自定义的settingItem类
点击需要listener
settingItem = (SettingItem) findViewById(R.id.settingitem_autoupdate); settingItem.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub } });
在onclick这个callback里需要实现在整个checkbox点击都有效果,要ID
点击后面的小框框没有作用,除了框框意外的地方点击后能实现开启、关闭的字样切换
@Override public void onClick(View v) { // 注意通过view v来找到ID CheckBox cb = (CheckBox) v.findViewById(R.id.cb_settingitem); TextView tv_setting_description = (TextView) v.findViewById(R.id.tv_setting_description); if(cb.isChecked()){ //勾上点击后要置成false cb.setChecked(false); tv_setting_description.setText("自动更新关闭"); }else{ cb.setChecked(true); tv_setting_description.setText("自动更新开启"); } } });
现在要保存用户对此项的设置,SharedPreferences,另外,由于之前一进去就是写死的显示是开启,我们应该根据保存状态来显示是开启还是关闭,所以这个通过ID来获取view应该拉出来通过settingitem获取,而不是在onclick里用v来获取控件在layout里写入的。这一部分的逻辑有点乱
public class SettingActivity extends Activity { private CheckBox cb; private TextView tv_setting_description; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.activity_setting); final SharedPreferences sp = getSharedPreferences("config", MODE_PRIVATE); SettingItem settingItem = (SettingItem) findViewById(R.id.settingitem_autoupdate); cb = (CheckBox) settingItem.findViewById(R.id.cb_settingitem); tv_setting_description = (TextView) settingItem.findViewById(R.id.tv_setting_description); //默认是true boolean ischeck= sp.getBoolean("autoupdate", true); cb.setChecked(ischeck); if (ischeck) { tv_setting_description.setText("自定更新开启"); } else { tv_setting_description.setText("自定更新关闭"); } settingItem.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Editor editor = sp.edit(); if(cb.isChecked()){ //勾上点击后要置成false cb.setChecked(false); tv_setting_description.setText("自动更新关闭"); editor.putBoolean("autoupdate", false); }else{ cb.setChecked(true); tv_setting_description.setText("自动更新开启"); editor.putBoolean("autoupdate", true); } editor.commit(); } }); } }
OK,现在要判断用户是否设置了自动更新再决定是否下载,回到splashActivity调用SharedPreferences
能这样直接调用enterHome()吗?如果用户没有设置自动更新,这样不就永远不会更新了?
如果用户没有设置自动更新,则应该是提示用户是否更新,需要给一个超时时间,而不是直接enterHome(),不能直接在主线程中等待,而是需要子线程,主线程只是刷UI滴哟
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_splash); TextView tv_splash_version = (TextView) findViewById(R.id.tv_splash_version); //上面的声明要注意是空字符串,而不是null tv_splash_version.setText("版本: "+getVersion()); //解析下载进度 tv_splash_downloadprogress = (TextView) findViewById(R.id.tv_splash_downloadprogress); //需要判断用户的设置,如果用户设置了自动更新,则就打开,else 直接进入主界面 SharedPreferences sp =getSharedPreferences("config", MODE_PRIVATE); if(sp.getBoolean("autoupdate", true)){ Update(); }else{ //如果用户没有设置自动更新,则应该是提示用户是否更新,需要给一个超时时间,而不是直接enterHome() //不能直接在主线程中等待,而是需要子线程 new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } //主线程睡后,由这个将enterHome交给主线程,相当于给主线程发了消息 runOnUiThread(new Runnable() { public void run() { enterHome(); } }); } }).start(); } }