<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:fsms="http://schemas.android.com/apk/res/com.hyz" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <com.hyz.TypedefRadioGroup android:id="@+id/radPayOrNot" android:layout_width="wrap_content" android:layout_height="wrap_content" > <com.hyz.TypedefRadioButton android:id="@+id/isPayDepositTrue" fsms:value="true" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="yes" android:textSize="18sp"/> <com.hyz.TypedefRadioButton android:id="@+id/isPayDepositFalse" fsms:value="false" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="no" android:textSize="18sp" /> <com.hyz.TypedefRadioButton android:id="@+id/isPayDepositFalse" fsms:value="false" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="A" android:textSize="18sp" /> <com.hyz.TypedefRadioButton android:id="@+id/isPayDepositFalse" fsms:value="false" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="B" android:textSize="18sp" /> </com.hyz.TypedefRadioGroup> </LinearLayout> <!-- 命名空间为fsms.路径是http://schemas.android.com/apk/res/这一部分是不变的, 后面接的是R的路径:rog.kandy.R。 然后在自定义控件的xml描述中就可以这样使用fsms:value="true"。 这样就实现了自定义控件的初始化赋值 -->
package com.hyz; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; import android.widget.CompoundButton; import android.widget.RadioButton; import android.widget.CompoundButton.OnCheckedChangeListener; public class TypedefRadioButton extends RadioButton implements OnCheckedChangeListener { private String mValue; public String getValue() { return this.mValue; } public void setValue(String value) { this.mValue = value; } public TypedefRadioButton(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // TODO Auto-generated constructor stub } public TypedefRadioButton(Context context, AttributeSet attrs) { super(context, attrs); try { /** * TypedArray其实就是一个存放资源的Array, * 首先从上下文中获取到R.styleable.RadioButton这个属性资源的资源数组。 * attrs是构造函数传进来,应该就是对应attrs.xml文件。 * a.getString(R.styleable.RadioButton_value); * 这句代码就是获取attrs.xml中定义的属性,并将这个属性的值传给本控件的mValue.最后, * 返回一个绑定结束的信号给资源:a.recycle();绑定结束。 */ TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.RadioButton); this.mValue = a.getString(R.styleable.RadioButton_value); a.recycle(); } catch (Exception e) { e.printStackTrace(); } setOnCheckedChangeListener(this); } public TypedefRadioButton(Context context) { super(context); // TODO Auto-generated constructor stub } public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { TypedefRadioGroup group = (TypedefRadioGroup) getParent(); group.setTheValue(this.getValue()); } }
package com.hyz; import android.content.Context; import android.util.AttributeSet; import android.widget.RadioGroup; import android.widget.RadioGroup.OnCheckedChangeListener; public class TypedefRadioGroup extends RadioGroup implements OnCheckedChangeListener { private String mValue; public TypedefRadioGroup(Context context, AttributeSet attrs) { super(context, attrs); this.setOnCheckedChangeListener(this); } public TypedefRadioGroup(Context context) { super(context); this.setOnCheckedChangeListener(this); } // 设置子控件的值 private void setChildValue() { int n = this.getChildCount(); for(int i=0;i<n;i++) { TypedefRadioButton radio = (TypedefRadioButton)this.getChildAt(i); if(radio.getValue().equals(this.mValue)) { radio.setChecked(false); } else { radio.setChecked(true); } } } // 获取子类的值 private void getChildValue() { int n = this.getChildCount(); for(int i=0;i<n;i++){ TypedefRadioButton radio = (TypedefRadioButton)this.getChildAt(i); if(radio.isChecked()){ this.mValue=radio.getValue(); } } } public void setTheValue(String value) { this.mValue = value; } public String getTheValue(){ getChildValue(); return this.mValue; } @Override public void onCheckedChanged(RadioGroup group, int checkedId) { setChildValue(); } }
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#aa0000"> <LinearLayout android:layout_width="fill_parent" android:layout_height="10dip" /> <LinearLayout android:layout_width="fill_parent" android:layout_height="40dip"> <com.hyz.TypedefTextView android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1" android:text="电影" android:gravity="center_vertical|center_horizontal" android:background="@drawable/button" android:focusable="true" android:clickable="true"/> <View android:layout_width="2px" android:layout_height="fill_parent" android:background="#ffffffff" /> <com.hyz.TypedefTextView android:layout_width="fill_parent" android:layout_height="fill_parent" android:clickable="true" android:layout_weight="1" android:text="电视" android:gravity="center_vertical|center_horizontal" android:background="@drawable/button" android:focusable="true" /> <View android:layout_width="2px" android:layout_height="fill_parent" android:background="#ffffffff" /> <com.hyz.TypedefTextView android:layout_width="fill_parent" android:layout_height="fill_parent" android:clickable="true" android:layout_weight="1" android:text="明星" android:gravity="center_vertical|center_horizontal" android:background="@drawable/button" android:focusable="true" /> </LinearLayout> </LinearLayout>
package com.hyz; import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.widget.TextView; import android.widget.Toast; public class TypedefTextView extends TextView { public TypedefTextView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // TODO Auto-generated constructor stub } /* * 当手指从按钮抬起,ACTION_UP 取消,ACTION_CANCEL 手指移出按钮,ACTION_OUTSIDE 另外,要返回false,因为返回true,系统将不会调用drawable/button.xml的效果, 因为true表示自己已经处理了onTouche事件,不需要别的逻辑再处理了。 */ public TypedefTextView(Context context, AttributeSet attrs) { this(context, attrs, 0); // TODO Auto-generated constructor stub this.setOnTouchListener(new OnTouchListener(){ public boolean onTouch(View v, MotionEvent event) { if (event.getAction()==MotionEvent.ACTION_CANCEL ||event.getAction()==MotionEvent.ACTION_UP ||event.getAction()==MotionEvent.ACTION_OUTSIDE) { Toast.makeText(getContext(), "touch", Toast.LENGTH_LONG).show(); } return false; } }); } public TypedefTextView(Context context) { super(context); // TODO Auto-generated constructor stub } }
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:my="http://schemas.android.com/apk/res/com.hyz" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <com.hyz.TypedefView android:layout_width="fill_parent" android:layout_height="wrap_content" my:textColor="#FFFFFFFF" my:textSize="22dp" /> </LinearLayout> <!-- * 如果使用自定义属性,那么在应用xml文件中需要加上新的schemas, * 比如这里是xmlns:my="http://schemas.android.com/apk/res/com.hyz" * 其中xmlns后的“my”是自定义的属性的前缀,res后的是我们自定义View所在的包 -->
package com.hyz; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.Style; import android.util.AttributeSet; import android.view.View; //这个出现在main.xml里 /** * 这个是自定义的TextView. * 至少需要重载构造方法和onDraw方法 * 对于自定义的View如果没有自己独特的属性,可以直接在xml文件中使用就可以了 * 如果含有自己独特的属性,那么就需要在构造函数中获取属性文件attrs.xml中自定义属性的名称 * 并根据需要设定默认值,放在在xml文件中没有定义。 * 如果使用自定义属性,那么在应用xml文件中需要加上新的schemas, * 比如这里是xmlns:my="http://schemas.android.com/apk/res/com.hyz" * 其中xmlns后的“my”是自定义的属性的前缀,res后的是我们自定义View所在的包 */ public class TypedefView extends View { Paint mPaint; //画笔,包含了画几何图形、文本等的样式和颜色信息 public TypedefView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // TODO Auto-generated constructor stub } public TypedefView(Context context, AttributeSet attrs) { super(context, attrs); mPaint = new Paint(); //TypedArray是一个用来存放由context.obtainStyledAttributes获得的属性的数组 //在使用完成后,一定要调用recycle方法 //属性的名称是styleable中的名称+“_”+属性名称 TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MyView); int textColor = array.getColor(R.styleable.MyView_textColor, 0XFF00FF00); //提供默认值,放置未指定 float textSize = array.getDimension(R.styleable.MyView_textSize, 36); mPaint.setColor(textColor); mPaint.setTextSize(textSize); array.recycle(); //一定要调用,否则这次的设定会对下次的使用造成影响 } public TypedefView(Context context) { super(context); // TODO Auto-generated constructor stub } public void onDraw(Canvas canvas){ super.onDraw(canvas); //Canvas中含有很多画图的接口,利用这些接口,我们可以画出我们想要的图形 //mPaint = new Paint(); //mPaint.setColor(Color.RED); mPaint.setStyle(Style.FILL); //设置填充 canvas.drawRect(10, 10, 100, 100, mPaint); //绘制矩形 mPaint.setColor(Color.BLUE); canvas.drawText("我是被画出来的", 10, 120, mPaint); } }
package com.hyz; import android.content.Context; import android.net.Uri; import android.preference.RingtonePreference; import android.util.AttributeSet; import android.content.Intent; import android.media.RingtoneManager; import android.util.Log; public class TypedefRingtonePreference extends RingtonePreference { private boolean mShowDefault;//是否在铃声列表中显示默认铃声选项,否则隐藏 private Uri mUri; public TypedefRingtonePreference(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); Log.i("cd", "a"); } //程序首先调用这个函数,其次onRestoreRingtone,再次onPrepareRingtonePickerIntent,最后onSaveRingtone public TypedefRingtonePreference(Context context, AttributeSet attrs) { super(context, attrs); //preference.xml里android:showDefault="true"设置显示“默认铃声”项,而下一句又可以将它隐藏 mShowDefault = getShowDefault(); //是否在铃声列表中显示默认铃声选项,否则隐藏 //getRingtoneType(); //getShowSilent();是否在铃声列表中显示静音选项,否则隐藏 Log.i("cd", "b"); } public TypedefRingtonePreference(Context context) { super(context); // TODO Auto-generated constructor stub Log.i("cd", "c"); } //此函数主要用来显示或隐藏铃声列表中某些铃声项 @Override protected void onPrepareRingtonePickerIntent(Intent ringtonePickerIntent) { // TODO Auto-generated method stub super.onPrepareRingtonePickerIntent(ringtonePickerIntent); Log.i("cd", "onPrepareRingtonePickerIntent"); //mShowDefault若为false,从列表隐藏”默认铃声“选项 ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, mShowDefault); //虽然android:showSilent="false",但下一句将”静音“选项显示在列表中 ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT,true); // if(mShowDefault) // { // Uri uri = Uri.parse(Settings.System.DEFAULT_RINGTONE_URI.toString()); // ringtonePickerIntent.putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, uri); // } } //此函数得到所有铃声项及上次所选铃声项 @Override protected Uri onRestoreRingtone() { // TODO Auto-generated method stub Log.i("cd", "onRestoreRingtone"); //此句话能够得到上一次设置的铃声列表以及上次所选铃声项 return RingtoneManager.getActualDefaultRingtoneUri(getContext(), getRingtoneType()); } //点击确定按钮后将保存铃声路径至自定义变量 @Override protected void onSaveRingtone(Uri ringtoneUri) {//注意这个方法 他是实现铃声设置的核心方法 Log.i("cd", "onSaveRingtone"); if(ringtoneUri!=null) { mUri = ringtoneUri; } //注意添加权限"android.permission.WRITE_SETTINGS" //保存所选铃声 //第一个参数表示上下文、第二个参数表示设置的铃声状态,第三个表示当前的歌曲uri RingtoneManager.setActualDefaultRingtoneUri(getContext(), getRingtoneType(), ringtoneUri); } }
package com.hyz; import android.app.AlertDialog.Builder; import android.content.Context; import android.content.DialogInterface; import android.preference.ListPreference; import android.util.AttributeSet; import android.util.Log; import android.widget.Toast; public class TypedefListPreference extends ListPreference { //用来保存ListPreference中的列表项的是否选择值 private boolean[] checkedItems; CharSequence[] entries ;//ListPreference.getEntries(),显示 在列表中的数据 CharSequence[] entryValues;//显示在summary里的值 public TypedefListPreference(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } public TypedefListPreference(Context context) { super(context); // TODO Auto-generated constructor stub } //点击ok或cancel后触发的事件,自定义视图事件 @Override protected void onDialogClosed(boolean positiveResult) { if(positiveResult) { CharSequence[] entryValues = getEntryValues(); StringBuilder str = new StringBuilder(); for(int i = 0 ; i < 7 ; i++) { if(checkedItems[i]) { str.append(entryValues[i]); } } setSummary(str); } } /*此函数复写后,如果函数体为空,则ListPreference对话框内容为空 * 删除此函数的话,系统将自动加载entryValues和entries为对话框的内容 * 因为为自定义的ListPreference,所以复写下面的方法为的就是可以自定义ListPreference对话框的显示内容 */ @Override protected void onPrepareDialogBuilder(Builder builder) { checkedItems = new boolean[7]; CharSequence[] entries = getEntries(); CharSequence[] entryValues = getEntryValues(); //删除preference.xml中的entries、entryValues将显示Toast if (entries == null || entryValues == null) { Toast.makeText(getContext(), "getEntries()或getEntryValues()为空", Toast.LENGTH_LONG).show(); } builder.setMultiChoiceItems(entries, checkedItems, new DialogInterface.OnMultiChoiceClickListener() { @Override public void onClick(DialogInterface dialog, int which, boolean isChecked) { checkedItems[which] = isChecked; } }); } }