<?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;
}
});
}
}