我对我的应用程序中使用的字体有一个对话框首选项。基本布局是一个 ListView,其中每一行由一个显示字体预览的 textView 和一个指示当前选择的字体的单选按钮组成。我希望用户能够通过单击行上的任意位置来设置首选项,但目前它仅在用户不单击单选按钮时才有效。有趣的是,一旦发生其他一些输入事件(例如滚动),单选按钮上的点击都会被处理。
这是我的代码:
ListView 的 XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ListView
android:id="@+id/fontStyleListView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true" >
</ListView>
</LinearLayout>
每一行:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<RadioButton
android:id="@+id/radioButton1"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:focusable="false"
android:focusableInTouchMode="false" />
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_toLeftOf="@id/radioButton1"
android:ellipsize="end"
android:focusable="false"
android:focusableInTouchMode="false"
android:maxLines="1"
android:paddingLeft="20dp" />
</RelativeLayout>
爪哇:
public class FontStylePreference extends DialogPreference
{
LayoutInflater li = LayoutInflater.from( getContext() );
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences( getContext() );
String[] fontStyleEntries = getContext().getResources().getStringArray( R.array.fontstyle_entries );
String[] fontStyleEntryValues = getContext().getResources().getStringArray( R.array.fontstyle_entryValues );
ListView listView;
public FontStylePreference(Context context, AttributeSet attrs)
{
super( context, attrs );
}
@Override
protected View onCreateDialogView()
{
super.onCreateDialogView();
LinearLayout layout = (LinearLayout) li.inflate( R.layout.fontstylepreference, null );
listView = (ListView) layout.getChildAt( 0 );
// Set adapter for contents.
FontStyleAdapter fontStyleAdapter = new FontStyleAdapter();
listView.setAdapter( fontStyleAdapter );
// Set onItemClickListener
ListViewItemClickListener listener = new ListViewItemClickListener();
listView.setOnItemClickListener( (android.widget.AdapterView.OnItemClickListener) listener );
return layout;
}
@Override
protected void onPrepareDialogBuilder(Builder builder)
{
builder.setPositiveButton( null, null );
super.onPrepareDialogBuilder( builder );
}
class FontStyleAdapter implements ListAdapter
{
ArrayList<RelativeLayout> radioTextViewArray = new ArrayList<RelativeLayout>( fontStyleEntries.length );
/**
* Constructor for FontStyleAdapter. Initializes contents of adapter.
*/
public FontStyleAdapter()
{
// get current font style so we know which one to check.
String currFontStyle = sharedPrefs.getString( getContext().getString( R.string.pref_key_font_style ),
"DejaVuSans" );
RelativeLayout row;
TextView textView;
RadioButton radioButton;
Typeface typeFace;
int fontSize = Integer
.valueOf( sharedPrefs.getString( getContext().getString( R.string.pref_key_font_size ), "14" ) );
if ( fontSize < 14 )
{
fontSize = 14;
}
for ( int i = 0; i < fontStyleEntries.length; i++ )
{
row = (RelativeLayout) li.inflate( R.layout.fontstylepreference_row, null );
radioButton = (RadioButton) row.getChildAt( 0 );
radioButton.setOnClickListener( new RadioButtonClickListener() );
textView = (TextView) row.getChildAt( 1 );
// set contents and style of each textView
textView.setText( fontStyleEntries[i] );
textView.setTextSize( TypedValue.COMPLEX_UNIT_PT, (float) (fontSize / 2) );
typeFace = Typeface.createFromAsset( getContext().getAssets(), "Fonts/" + fontStyleEntryValues[i]
+ ".ttf" );
textView.setTypeface( typeFace );
if ( currFontStyle.equals( fontStyleEntryValues[i] ) )
{
radioButton.setChecked( true );
}
radioTextViewArray.add( row );
}
}
@Override
public int getCount()
{
return fontStyleEntries.length;
}
@Override
public Object getItem(int position)
{
return radioTextViewArray.get( position );
}
@Override
public long getItemId(int position)
{
return radioTextViewArray.get( position ).getId();
}
@Override
public int getItemViewType(int position)
{
// Leave this as 0 to indicate we only use one type of view in this
// list.
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
convertView = radioTextViewArray.get( position );
int minHeight = (int) (50 * getContext().getResources().getDisplayMetrics().density);
convertView.setMinimumHeight( minHeight );
return convertView;
}
@Override
public int getViewTypeCount()
{
// Leave this as 1 to indicate we only use one type of view in this
// list.
return 1;
}
@Override
public boolean hasStableIds()
{
return false;
}
@Override
public boolean isEmpty()
{
return radioTextViewArray.isEmpty();
}
@Override
public void registerDataSetObserver(DataSetObserver observer)
{
}
@Override
public void unregisterDataSetObserver(DataSetObserver observer)
{
}
@Override
public boolean areAllItemsEnabled()
{
return true;
}
@Override
public boolean isEnabled(int position)
{
return true;
}
}
class ListViewItemClickListener implements OnItemClickListener
{
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
String font = fontStyleEntryValues[position];
sharedPrefs.edit().putString( getKey(), font ).commit();
Dialog dialog = (Dialog) getDialog();
if ( dialog != null )
{
dialog.dismiss();
}
}
}
class RadioButtonClickListener implements OnClickListener
{
@Override
public void onClick(View v)
{
int position = listView.getPositionForView( v );
if ( position != AdapterView.INVALID_POSITION )
{
String font = fontStyleEntryValues[position];
sharedPrefs.edit().putString( getKey(), font ).commit();
// Check if we can get the dialog. A few times the program has crashed here, maybe
// because it is already dismissed.
Dialog dialog = (Dialog) getDialog();
if ( dialog != null )
{
dialog.dismiss();
}
}
}
}
}