onItemClick和onItemSelected方法的4个参数详细解析

关于ListView和GridView的onItemClick和onItemSelected方法的4个参数,网上有许多文章都有提及,但大多只是按照Android API的英文描述简单翻译一下,接下来我将举例详细解析这4个参数。

由于ListView和GridView的onItemClick和onItemSelected方法的4个参数大抵相同,下面我就以ListView的onItemClick举例说明:

首先,在activity_main.xml文件里面定义两个简单的ListView, 代码如下:




    
    

    
    

Java代码也很简单,MainActivity.java代码如下:
package com.example.androidtest;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class MainActivity extends Activity implements OnItemClickListener {

	private static final String TAG = "MainActivity";

	private ListView mListView1;
	private ListView mListView2;
	private ArrayAdapter mArrayAdapter1;
	private ArrayAdapter mArrayAdapter2;

	private String[] cities1 = { "北京", "天津", "上海" };
	private String[] cities2 = { "广州", "深圳" };

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.activity_main);
		initView();
	}

	private void initView() {
		mArrayAdapter1 = new ArrayAdapter(this, android.R.layout.simple_list_item_1, cities1);
		mArrayAdapter2 = new ArrayAdapter(this, android.R.layout.simple_list_item_1, cities2);
		mListView1 = (ListView) findViewById(R.id.list1);
		mListView2 = (ListView) findViewById(R.id.list2);

		mListView1.setAdapter(mArrayAdapter1);
		mListView2.setAdapter(mArrayAdapter2);
		mListView1.setOnItemClickListener(this);
		mListView2.setOnItemClickListener(this);
	}

	@Override
	public void onItemClick(AdapterView parent, View view, int position, long id) {
		Log.d(TAG, "onItemClick: parent = " + parent);
		Log.d(TAG, "onItemClick: view = " + view);
		Log.d(TAG, "onItemClick: position = " + position + ", id = " + id);
	}

}
编译启动APK后界面如下:

      onItemClick和onItemSelected方法的4个参数详细解析_第1张图片

下面我们点击北京,打印日志如下:(注意看标红框的地方)

onItemClick和onItemSelected方法的4个参数详细解析_第2张图片

点击天津,打印日志如下:

onItemClick和onItemSelected方法的4个参数详细解析_第3张图片

从上面两个日志可以看出:第一个ListView在窗口的位置(除通知栏和标题栏以外的屏幕位置):0,0-1080,600表示x起点坐标为0,y起点坐标为0;x终点坐标为1080, y终点坐标为600和xml id:id/list1;以及第一项和第二项(item)在窗口的位置(0,0-1080,1920,194-1080,386),这里大家可能会有疑问,你不是说第一项终点坐标是192么,怎么第二项起点坐标变成了194呢?其实这是因为每一项之间的分隔线占用了2个像素的高度,大家可以去activity_main.xml里面加上android:divider="@null"去掉分隔线再打印日志看看

接下来我们修改MainActivity.java中的打印日志代码来做进一步验证:

@Override
	public void onItemClick(AdapterView parent, View view, int position, long id) {
		int itemCount = parent.getCount();
		int parentWidth = parent.getWidth();
		int parentHeight = parent.getHeight();
		int viewWidth = view.getWidth();
		int viewheight = view.getHeight();
		Log.d(TAG, "onItemClick: itemCount = " + itemCount + ", parentWidth = " + parentWidth + ", parentHeight = " + parentHeight 
				+ ", viewWidth = " + viewWidth + ", viewheight = " + viewheight + ", position = " + position + ", id = " + id);
	}
重新编译启动APK后,点击北京后,打印日志如下:


点击广州,打印日志如下:


综上所述,第一个参数parent表示我们点击的是哪一个ListView,包括ListView位置、id以及总共有多少个item等;第二个参数view表示我们点击的是ListView上面的某一项(item)。好了,前面两个参数讲完了,下面讲后面两个参数positionid.

从上面日志中可以看出来,点击北京,position = 0,点击天津,position = 1,即第三个参数position表示点击的item的是第几行,从0开始。相信大家也看到了,上面日志中打印的position和id是相同的,那么第四个参数是不是跟第三个参数一样呢,相信Google开发者不会做这样的事情。。通常情况下第三个参数和第四个参数的值是相等的,但也有不相等的时候,以下通过一个简单的获取手机媒体库音乐的例子来进行说明:

首先,在activity_test.xml文件里面定义一个简单的ListView,代码如下:




    
    

TestActivity.java代码如下:

package com.example.androidtest;

import android.app.Activity;
import android.app.LoaderManager;
import android.content.Context;
import android.content.CursorLoader;
import android.content.Loader;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.CursorAdapter;
import android.widget.ListView;
import android.widget.TextView;

public class TestActivity extends Activity implements OnItemClickListener, LoaderManager.LoaderCallbacks {

	private static final String TAG = "TestActivity";
	private Context mContext;
	private Cursor mCursor;

	private MusicListAdapter musicListAdapter;
	private ListView mListView;

	private String[] projection = new String[] { MediaStore.Audio.Media._ID, MediaStore.Audio.Media.DISPLAY_NAME, MediaStore.Audio.Media.DATA };

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.activity_test);
		initView();

		// LoaderManager初始化
		getLoaderManager().initLoader(0, null, this);
	}

	private void initView() {
		mContext = this;
		musicListAdapter = new MusicListAdapter(mContext, null, false);
		mListView = (ListView) findViewById(R.id.music_list);
		mListView.setAdapter(musicListAdapter);
		mListView.setOnItemClickListener(this);
	}

	@Override
	public void onItemClick(AdapterView parent, View view, int position, long id) {
		Log.d(TAG, "onItemClick: position = " + position + ", id = " + id);
		// 获取媒体库音乐id
		String audioId = mCursor.getString(mCursor.getColumnIndex(MediaStore.Audio.Media._ID));
		Log.d(TAG, "onItemClick: audioId = " + audioId);
		// 获取媒体库uri路径
		Uri uri = Uri.withAppendedPath(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, audioId);
		Log.d(TAG, "onItemClick: uri = " + uri);
	}

	@Override
	public Loader onCreateLoader(int id, Bundle args) {
		try {
			return new CursorLoader(mContext, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, null, null, null);
		} catch (Exception e) {
			Log.e(TAG, "onCreateLoader: Exception || " + Log.getStackTraceString(e));
			return null;
		}
	}

	@Override
	public void onLoadFinished(Loader loader, Cursor data) {
		mCursor = data;
		musicListAdapter.changeCursor(data);
	}

	@Override
	public void onLoaderReset(Loader loader) {
		// TODO Auto-generated method stub
	}

	class MusicListAdapter extends CursorAdapter {

		private final LayoutInflater mInflater;

		public MusicListAdapter(Context context, Cursor c, boolean autoRequery) {
			super(context, c, false);
			mInflater = LayoutInflater.from(context);
		}

		class ViewHolder {
			TextView name;
		}

		@Override
		public View newView(Context context, Cursor cursor, ViewGroup parent) {
			ViewHolder vh = new ViewHolder();
			View view = mInflater.inflate(android.R.layout.simple_list_item_1, null);
			vh.name = (TextView) view.findViewById(android.R.id.text1);
			view.setTag(vh);
			return view;
		}

		@Override
		public void bindView(View view, Context context, Cursor cursor) {
			ViewHolder vh = (ViewHolder) view.getTag();
			// 获取媒体库音乐名称
			String name = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME));
			vh.name.setText(name);
		}
	}

}

注意要在AndroidManifest.xml加上权限:

编译启动APK后界面如下:

onItemClick和onItemSelected方法的4个参数详细解析_第4张图片

下面我们点击第一项, 打印日志如下:


点击第二项,打印日志如下:


由上面两个日志可以看出,position和id的值不相等了,id表示的是媒体库MediaStore音频的id。大家可以用sqlite命令去/data/data/com.android.providers.media/databases/external.db验证一下。

综上所述,id表示的是item在数据库中某行的id,如果找不到该id, 则和第三个参数position的值相同。

最后我们来总结一下这四个参数在实际工作中的用途:

parent:用得很少,可以用parent.getId()来获取ListView或GridView的id,parent.getCount()来获取item总数目。

view:用得很少,当我们开发机顶盒或智能电视应用时,点击遥控器方向键,如果需要实现焦点框平滑移动的动画效果(为了提高用户体验),这个参数就用得上了,我们只要计算焦点框从一个view移动到另外一个view的位置和view的大小,利用Android自带的动画API,即可实现。

position:用得最多的就是这个参数了,平常工作中我们基本上只需要用到这个参数。

id:用得很少,虽然可以用来表示数据库row id,但我们也可以用mCursor.getString(mCursor.getColumnIndex(MediaStore.Audio.Media._ID))来做同样的事。

你可能感兴趣的:(Android)