Ctrl+T可以知道这个类的所有子类和父类。
如果你每个页面都有相同的布局,那么你就可以在 style文件里面定义一个相同的style。
然后这样就可以防止代码的重复使用。
给你的控件设置
如果你设置的是marquee(跑马灯)就是一个滚动效果 如果你设置为none就是不设置点。
获取焦点:
android:focusable="true"
android:focusableInTouchMode="true"
————————
自定义控件:自动获取焦点
1.自定义控件编写流程
创建一个默认就能获取焦点的TextView
1.创建一个类继承至TextView,FocusTextView
2.重写其构造方法
public class FocusTextView extends TextView {
//使用在通过java代码创建控件
public FocusTextView(Context context) {
super(context);
}
//由系统调用(带属性+上下文环境构造方法)
public FocusTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
//由系统调用(带属性+上下文环境构造方法+布局文件中定义样式文件构造方法)
public FocusTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
//重写获取焦点的方法,由系统调用,调用的时候默认就能获取焦点
@Override
public boolean isFocused() {//对应xml里面的 android:focusable="true"和android:focusableInTouchMode="true"
return true;
}
}
4.使用过程获取当前类的全路径名称,作为xml中的标签存在,其余属性的使用方式和TextView一致
————————————————————————
2,GridView使用,和ListView使用方式类似
列数(3列)
数据填充(模块名称,模块图片)
数据适配器一致的
注意一点你设置适配器的时候,定义的布局文件中的控件一定要居中!!!
ImageView 有一个方法 setBackgroundResource(int id) 这个方法可以传递一个图片的id
进来 然后设置给这个控件.
传递的id为R.drawable.xxxxxx
————————————
当你需要设置一个控件,当做一条线的时候。直接使用
————————————————————————————
3,自定义组合控件
1.将已经编写好的布局文件,抽取到一个类中去做管理,下次还需要使用此布局结构的时候,
直接使用组合控件对应的对象.
记住最后一个参数要写this,因为我们需要将前面抽取出来的控件作为一个root(根),让他加载到我们现在这个类里面。
public class SettingItemView extends RelativeLayout {public SettingItemView(Context context) {
this(context,null);
}
public SettingItemView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public SettingItemView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
//xml--->view 将设置界面的一个条目转换成view对象,直接添加到了当前SettingItemView对应的view中
View.inflate(context, R.layout.setting_item_view, this);
//等同于以下两行代码
/*View view = View.inflate(context, R.layout.setting_item_view, null);
this.addView(view);*/
//自定义组合控件中的标题描述
TextView tv_title = (TextView) findViewById(R.id.tv_title);
tv_des = (TextView) findViewById(R.id.tv_des);
cb_box = (CheckBox) findViewById(R.id.cb_box);
}
然后在SettingActivity中设置找到控件,并给他设置监听
4,设置界面,事件传递过程CheckBox响应当前的点击事件,则SettingItemView就不能再去响应此事件,不能调用onClick方法,去改变状态
这个是第一种方式:
让我们的外部控件事件传递给内部控件,然后内部控件不去响应事件,在回传给外部控件。
第二种方式:
让我们的事件直接不能传递给内部控件,只能在外部控件。这个要去重写事件响应的API
这里我们使用第一种方式。
解决此问题的方案为:不让checkBox响应点击事件
sputil类:
用来保存一些配置。
比如保存你的checkBox的勾选情况,下次进来的时候可以自动使用上次的勾选。
public class SpUtil {
private static SharedPreferences sp;
/**
* 写入boolean变量至sp中
* @param ctx 上下文环境
* @param key 存储节点名称
* @param value 存储节点的值 boolean
*/
public static void putBoolean(Context ctx,String key,boolean value){
//(存储节点文件名称,读写方式)
if(sp == null){
sp = ctx.getSharedPreferences("config", Context.MODE_PRIVATE);
}
sp.edit().putBoolean(key, value).commit();
}
/**
* 读取boolean标示从sp中
* @param ctx 上下文环境
* @param key 存储节点名称
* @param defValue 没有此节点默认值
* @return 默认值或者此节点读取到的结果
*/
public static boolean getBoolean(Context ctx,String key,boolean defValue){
//(存储节点文件名称,读写方式)
if(sp == null){
sp = ctx.getSharedPreferences("config", Context.MODE_PRIVATE);
}
return sp.getBoolean(key, defValue);
}
如果你在其他类调用这个类的方法的时候。
//获取已有的开关状态,用作显示
boolean open_update = SpUtil.getBoolean(this, ConstantValue.OPEN_UPDATE, false);
//是否选中,根据上一次存储的结果去做决定
siv_update.setCheck(open_update);
public class ConstantValue {
/**
* 是否开启更新的key
*/
public static final String OPEN_UPDATE = "open_update";
/**
* 是否设置密码key
*/
public static final String MOBILE_SAFE_PSD = "mobile_safe_psd";
}
注意一个问题:
private void initUpdate() {
final SettingItemView siv_update = (SettingItemView) findViewById(R.id.siv_update);
//获取已有的开关状态,用作显示
boolean open_update = SpUtil.getBoolean(this, ConstantValue.OPEN_UPDATE, false);
//是否选中,根据上一次存储的结果去做决定
siv_update.setCheck(open_update);
siv_update.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//如果之前是选中的,点击过后,变成未选中
//如果之前是未选中的,点击过后,变成选中
//获取之前的选中状态
boolean isCheck = siv_update.isCheck();
//将原有状态取反,等同上诉的两部操作
siv_update.setCheck(!isCheck);
//将取反后的状态存储到相应sp中
SpUtil.putBoolean(getApplicationContext(), ConstantValue.OPEN_UPDATE,!isCheck);
}
});
我们这里在onclicklistener()
里面去保存isCheck的状态的时候 调用SpUtil类的时候传递进去的context 不能是this
因为在
new OnClickListener()
这个内部类里面的this 是这个类的对象。
我们需要的context是activity里面的对象。所以我们需要用getApplicationContext();
_________________________________________
mHandler.sendMessageDelayed(msg, 4000);
//在发送消息4秒后去处理,ENTER_HOME状态码指向的消息
mHandler.sendEmptyMessageDelayed(ENTER_HOME, 4000);
这两个方法就是延时的去处理消息,不是延时去发送消息.
_______________________________________________________________
5,自定义属性,(设置中心,有多个条目,在复用SettingItemView的时候,每一个条目对应的标示,描述内容都不一致)
1.查看源码,定义属性时候做法
sdk所在目录\platforms\android-16\data\res\values\attrs.xml
2.给SettingItemView定义属性,工程res\values\attrs.xml
3.自定义属性的使用
Android之所以能用控件的属性,比如
这样就相当于连接到了这个文件的目录下定义好的属性。
所以我们要使用自定义的属性也需要给它命名空间。
定义名空间namespace
mobilesafe替换掉原有android
com.itheima.mobilesafe74必须这样编写,替换掉了android,代表当前应用自定义属性
xmlns:mobilesafe="http://schemas.android.com/apk/res/com.itheima.mobilesafe74"
android:id="@+id/siv_update"
android:layout_width="match_parent"
android:layout_height="wrap_content"
mobilesafe:destitle="自动更新设置"
mobilesafe:desoff="自动更新已关闭"
mobilesafe:deson="自动更新已开启">
4.获取属性值
mobilesafe:destitle="自动更新设置"
mobilesafe:desoff="自动更新已关闭"
mobilesafe:deson="自动更新已开启"
以上的是哪个属性都需要给自定义组合控件(SettingItemView)内部的两个TextView去使用,获取属性值
//通过属性索引获取属性名称&属性值
for(int i=0;i
public class SettingItemView extends RelativeLayout {
private static final String NAMESPACE = "http://schemas.android.com/apk/res/com.itheima.mobilesafe74";
private static final String tag = "SettingItemView";
private CheckBox cb_box;
private TextView tv_des;
private String mDestitle;
private String mDesoff;
private String mDeson;
public SettingItemView(Context context) {
this(context,null);
}
public SettingItemView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public SettingItemView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
//xml--->view 将设置界面的一个条目转换成view对象,直接添加到了当前SettingItemView对应的view中
View.inflate(context, R.layout.setting_item_view, this);
//等同于以下两行代码
/*View view = View.inflate(context, R.layout.setting_item_view, null);
this.addView(view);*/
//自定义组合控件中的标题描述
TextView tv_title = (TextView) findViewById(R.id.tv_title);
tv_des = (TextView) findViewById(R.id.tv_des);
cb_box = (CheckBox) findViewById(R.id.cb_box);
//获取自定义以及原生属性的操作,写在此处,AttributeSet attrs对象中获取
initAttrs(attrs);
//获取布局文件中定义的字符串,赋值给自定义组合控件的标题
tv_title.setText(mDestitle);
}
/**
* 返回属性集合中自定义属性属性值
* @param attrs 构造方法中维护好的属性集合
*/
private void initAttrs(AttributeSet attrs) {
/*//获取属性的总个数
Log.i(tag, "attrs.getAttributeCount() = "+attrs.getAttributeCount());
//获取属性名称以及属性值
for(int i=0;i
注意事项:当我们需要重写一个自定义控件的自定义属性的时候。
我们需要在这个工程的values文件下面创一个attrs.xml
————————————————————————————————
6,自定义对话框
这里我们同理用spUtil来保存密码,将key设置为常量类里面的常量。即可
自定义对话框步骤:
第一步我们new出对话框的Builder对象。
然后因为我们要定义自己的布局对话框界面。
所以第二步我们要创建一个对话框。
第三步就是调用setView方法,去使用一个布局文件。
就是使用xml---->view对象(使用infate)
技巧:TextUtils.isEmpty(str) 这个方法可以判断str是否为""(空字符串) 或者为null
这里会出现button空指针异常。因为你直接使用findViewById是 在当前控件指定的布局文件中去找控件。
但是你现在要使用的button 是在view中的。所以我们需要使用view.findviewbyid.
/**
* 设置密码对话框
*/
private void showSetPsdDialog() {
//因为需要去自己定义对话框的展示样式,所以需要调用dialog.setView(view);
//view是由自己编写的xml转换成的view对象xml----->view
Builder builder = new AlertDialog.Builder(this);
final AlertDialog dialog = builder.create();
final View view = View.inflate(this, R.layout.dialog_set_psd, null);
//让对话框显示一个自己定义的对话框界面效果
dialog.setView(view);
dialog.show();
Button bt_submit = (Button) view.findViewById(R.id.bt_submit);
Button bt_cancel = (Button) view.findViewById(R.id.bt_cancel);
bt_submit.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
EditText et_set_psd = (EditText) view.findViewById(R.id.et_set_psd);
EditText et_confirm_psd = (EditText)view.findViewById(R.id.et_confirm_psd);
String psd = et_set_psd.getText().toString();
String confirmPsd = et_confirm_psd.getText().toString();
if(!TextUtils.isEmpty(psd) && !TextUtils.isEmpty(confirmPsd)){
if(psd.equals(confirmPsd)){
//进入应用手机防盗模块,开启一个新的activity
Intent intent = new Intent(getApplicationContext(), TestActivity.class);
startActivity(intent);
//跳转到新的界面以后需要去隐藏对话框
dialog.dismiss();
SpUtil.putString(getApplicationContext(), ConstantValue.MOBILE_SAFE_PSD, psd);
}else{
ToastUtil.show(getApplicationContext(),"确认密码错误");
}
}else{
//提示用户密码输入有为空的情况
ToastUtil.show(getApplicationContext(), "请输入密码");
}
}
});
bt_cancel.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
}
});
}
md5加密:将字符串转换成 32位的字符串(16进制字符(0~f)) 不可逆
import java.beans.Encoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class Md5Util {
/**
* @param args
*/
public static void main(String[] args) {
//加盐
String psd = "123"+"abc";
encoder(psd);
}
/**给指定字符串按照md5算法去加密
* @param psd 需要加密的密码
*/
private static void encoder(String psd) {
try {
//1,指定加密算法类型
MessageDigest digest = MessageDigest.getInstance("MD5");
//2,将需要加密的字符串中转换成byte类型的数组,然后进行随机哈希过程
byte[] bs = digest.digest(psd.getBytes());
// System.out.println(bs.length);
//3,循环遍历bs,然后让其生成32位字符串,固定写法
//4,拼接字符串过程
StringBuffer stringBuffer = new StringBuffer();
for (byte b : bs) {
int i = b & 0xff;
//int类型的i需要转换成16机制字符
String hexString = Integer.toHexString(i);
// System.out.println(hexString);
if(hexString.length()<2){
hexString = "0"+hexString;
}
stringBuffer.append(hexString);
}
//5,打印测试
System.out.println(stringBuffer.toString());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
}