鱼鱼Chen之学写自己的apk(三) 自定义漂亮的Spinner

本文介绍了如何自定义Spinner样式,通过分析结构、创建适配器Adapter,实现选中框和下拉框的定制效果。适配器继承自ArrayAdapter,重写了getView和getDropDownView方法,并提供了布局XML代码示例。文章最后分享了完整的代码链接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一开始学Spinner的时候,网上绝大数资料就是随便一写带过,很少有提到自定义款式的。要不然就不是满意的效果,当然,此篇也只仅供参考,不一定是你要的效果。没有用到style,所以没法更深度的定制,但是我觉得听美观的了。说了那么多废话,下面进入正题吧~

一、分析一下结构


很简单,主Activity和一个自定义的Spinner的Adapter,布局的话,主布局和Spinner的两个款式布局(选中框和下拉框) 效果如下:


二、首先,写我们的适配器Adapter

我们让其继承至ArrayAdapter,<E>写作CharSequence,这个是字符队列。算作是String的子类,String可以强转,前者用tostring方法向上转型。接着,我们写入构造方法。

</pre><pre name="code" class="java">private Context context;
	private int resourceId;
	private ViewHolder holder;
	private int currentIndex = -1;
	private int[] pics = { R.drawable.shengdan01, R.drawable.shengdan02,
			R.drawable.shengdan03, R.drawable.shengdan04,
			R.drawable.shengdan05, R.drawable.shengdan06 };

	public SpinnerAdapter(Context context, int resource,
			CharSequence[] itemCharSequences) {
		super(context, resource, itemCharSequences);
		this.context = context;
		this.resourceId = resource;
	}
我顺便把要申明的变量列出来了。

接着,重写两个方法getView和getDropDownView

@Override
	public View getDropDownView(int position, View convertView, ViewGroup parent) {
		View view=LayoutInflater.from(context).inflate(R.layout.spinner_drop_item, null);
		TextView textDrop=(TextView) view.findViewById(R.id.text_drop);
		ImageView imageDrop=(ImageView) view.findViewById(R.id.image_drop);
		textDrop.setText(getItem(position));
		imageDrop.setImageResource(pics[position]);
		if (currentIndex == position) {
			holder.selectDrop.setVisibility(View.VISIBLE);
		}
		return view;
	}

下面是spinner_drop_item的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="horizontal" 
    android:layout_marginLeft="8dp"
    android:layout_marginRight="8dp"
    android:background="#ffecce">

    <ImageView
        android:id="@+id/image_drop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical" />

    <TextView
        android:id="@+id/text_drop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="30dp"
        android:layout_gravity="center_vertical"
        android:textSize="25sp" />

    <ImageView
        android:id="@+id/select_drop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="150dp"
        android:background="@drawable/spinner_is_selected"
        android:visibility="invisible" />

</LinearLayout>
原理呢,其实很简单,这里的布局应用到的是每个下拉列表项。这么一说,前面的getDropDown方法就不多解释了,还是很好理解的。至于currentIndex是什么呢?我们看了getView方法就明白了
@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		View view = LayoutInflater.from(context).inflate(resourceId, null);
		TextView textView = (TextView) view.findViewById(R.id.text_test);
		TextView textIndex=(TextView) view.findViewById(R.id.text_index);
		textView.setText(getItem(position));
		textIndex.setText("选中第"+(position+1)+"项");
		currentIndex = position;
		return view;
	}
这边就是选框的View,先不上布局。我们理解一下,其实是每次选中某个下拉列表项后,都会执行这个方法。这时候我们把选中的项传给一个int(即currentIndex)。下次打开下拉列表,就会执行getDropDownView方法,就会让对应的position的列表显示勾勾图标!

接着,上spinner_item.xml。同样,没什么难点。这边的resourceId,我们在构造方法里看到是传入的,等会儿会在主Activity里写到,就是spinner_item.xml(layout)

<?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="horizontal">

    <TextView
        android:id="@+id/text_test"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="25sp" />
    <TextView
        android:id="@+id/text_index"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="15sp"
        android:layout_marginLeft="150dp"/>

</LinearLayout>
三、写主Activity

布局没什么好说的,直接拉一个spinner即可。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.dota.example.fishychenofspinner.MainActivity" >

    <Spinner
        android:id="@+id/spinner_test"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="8dp"
        android:background="@drawable/selector_spinner_background" />

</LinearLayout>
主Activity主要就是init方法
private void init() {
		CharSequence itemsCharSequence[] = getResources().getTextArray(
				R.array.spinner_item_name);
		spinner = (Spinner) findViewById(R.id.spinner_test);
		adapter = new SpinnerAdapter(MainActivity.this, R.layout.spinner_item,
				itemsCharSequence);
		spinner.setAdapter(adapter);
		spinner.setOnItemSelectedListener(this);
	}
这里的R.layout.spinner_item就是我们等会儿要传入的布局

顺便提一下关于使用string-array的方法。在values/strings里申明如下格式

 <string-array name="spinner_item_name">
        <item name="spinner_candy">糖果</item>
        <item name="spinner_tree">圣诞树</item>
        <item name="spinner_snowman">雪人</item>
        <item name="spinner_gift">礼物</item>
        <item name="spinner_lolipop">棒棒糖</item>
        <item name="spinner_socks">袜子</item>
    </string-array>
然后调用getResource方法的getTextArray即可了。onitemSelectedListener跟onitemClick类似,直接看英文就明白了。下面是完整的主Activity代码
public class MainActivity extends Activity implements OnItemSelectedListener {
	private SpinnerAdapter adapter;
	private Spinner spinner;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		init();
	}

	private void init() {
		CharSequence itemsCharSequence[] = getResources().getTextArray(
				R.array.spinner_item_name);
		spinner = (Spinner) findViewById(R.id.spinner_test);
		adapter = new SpinnerAdapter(MainActivity.this, R.layout.spinner_item,
				itemsCharSequence);
		spinner.setAdapter(adapter);
		spinner.setOnItemSelectedListener(this);
	}

	@Override
	public void onItemSelected(AdapterView<?> parent, View view, int position,
			long id) {
		Toast.makeText(MainActivity.this, "您选中的是第" + position + "项",
				Toast.LENGTH_SHORT).show();
	}

	@Override
	public void onNothingSelected(AdapterView<?> parent) {
		// TODO Auto-generated method stub

	}
}
四、优化

关于getView我觉得没有必要优化,毕竟只加载一个。但是DropView的话,如果下拉列表项多了,每次打开多浪费资源啊。这里用到的原理就是listview用到的ViewHolder原理。改良后代码如下:

@Override
	public View getDropDownView(int position, View convertView, ViewGroup parent) {
		View view;
		if (convertView == null) {
			view = LayoutInflater.from(context).inflate(
					R.layout.spinner_drop_item, parent, false);
			holder = new ViewHolder();
			holder.textDrop = (TextView) view.findViewById(R.id.text_drop);
			holder.imageDrop = (ImageView) view.findViewById(R.id.image_drop);
			holder.selectDrop = (ImageView) view.findViewById(R.id.select_drop);
			view.setTag(holder);
		} else {
			view = convertView;
			holder = (ViewHolder) view.getTag();
		}
		holder.textDrop.setText(getItem(position));
		holder.imageDrop.setImageResource(pics[position]);
		if (currentIndex == position) {
			holder.selectDrop.setVisibility(View.VISIBLE);
		}
		return view;
	}
并新加一个类
class ViewHolder {
	TextView textDrop;
	ImageView imageDrop;
	ImageView selectDrop;
}
记得holder是类的实例对象。原理大致就是,把要设置的那些控件封装到ViewHolder里,每次打开下拉列表的时候。先判断,如果缓存里有的话,就直接拿出来用,不再新开资源。第一次创建的时候用setTag方法设置标识,以后调用的时候用getTag取出对应标识即可。这样,当列表项足够多的时候,就不会卡了~~

怎么样,用还算简单的方法就可以做出还不错的自定义spinner了~

老样子,完整代码的百度云链接:

http://pan.baidu.com/s/1mgzKESC




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值