gridview的item放大问题,setOnItemSelectedListener不执行的解决办法。

转载请注明出处,谢谢:http://blog.csdn.net/harryweasley/article/details/46858019


提前声明:本篇博客是基于电视机顶盒的,全部操作是用遥控器。


我要实现这样的一个效果。点击gridview的item,有放大的效果。

先看下效果图。








本篇博客的重难点:

1.怎么让选中的item变大。

2.变大后,怎么让item全部显示出来,而不是被gridview的边缘挡住。

3.怎么每次进入gridview当前item变大。即解决setOnItemSelectedListener不响应的方法。


我先将我的代码分开,来分别讲解着三个重点,之后会将整个源码上传。


1.怎么让选中的item变大。


在BaseAdapter里的getView方法中,进行如下的判断。

@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			ViewHolder holder;
			if (convertView == null) {
				convertView = LayoutInflater.from(context).inflate(
						R.layout.item_app_wall2, parent, false);
				holder = new ViewHolder();
				holder.icon = (ImageView) convertView
						.findViewById(R.id.app_icon);
				holder.name = (TextView) convertView
						.findViewById(R.id.app_name);
				holder.size = (TextView) convertView
						.findViewById(R.id.app_size);
				holder.count = (TextView) convertView
						.findViewById(R.id.app_count);
				convertView.setTag(holder);
			} else {
				holder = (ViewHolder) convertView.getTag();
			}
			if (selected == position) {
				// 如果选中的是当前item,则将当前item变大。
				convertView.bringToFront();
				animEffect.setAttributs(1.0F, 1.0366F, 1.0F, 1.0366F, 100L);
				Animation localAnimation = animEffect.createAnimation();
				convertView.startAnimation(localAnimation);
			}
			if (last == position) {
				// 将上一个选中的item恢复原样。
				animEffect.setAttributs(1.0366F, 1.0F, 1.0366F, 1.0F, 0L);
				convertView.startAnimation(animEffect.createAnimation());
			}
			return convertView;
		}


然后在代码里,调用appWallBaseAdapter.notifyDataSetChanged()该方法。如下所示:

appGrid.setOnItemSelectedListener(new OnItemSelectedListener() {

			@Override
			public void onItemSelected(AdapterView<?> parent, View view,
					int position, long id) {
				Log.i("tag", "OnItemSelectedListener执行了");
				isSelect = true;
				last = selected;
				selected = position;
				appWallBaseAdapter.notifyDataSetChanged();
				appGrid.smoothScrollToPositionFromTop(position, 300);

			}

			@Override
			public void onNothingSelected(AdapterView<?> parent) {
				Log.i("tag", "");
			}
		});


如果是当前选中的item,则直接将convertView变大。其中animEffect是自定义的。

/**
	 * 自定义动画类
	 */
	ScaleAnimEffect animEffect = new ScaleAnimEffect();



ScaleAnimEffect类里的内容是:

package com.example.test;

import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.ScaleAnimation;

public class ScaleAnimEffect {
	private long duration;
	private float fromXScale;
	private float fromYScale;
	private float toXScale;
	private float toYScale;

	public void setAttributs(float paramFloat1, float paramFloat2,
			float paramFloat3, float paramFloat4, long paramLong) {
		this.fromXScale = paramFloat1;
		this.fromYScale = paramFloat3;
		this.toXScale = paramFloat2;
		this.toYScale = paramFloat4;
		this.duration = paramLong;
	}

	public Animation createAnimation() {
		/**
		 * @param fromX
		 *            动画开始前水平方向的伸缩比例大小
		 * @param toX
		 *            动画结束后,水平方向的伸缩比例大小
		 * @param fromY
		 *            动画开始前,竖直方向的比例大小
		 * @param toY
		 *            动画结束结束后,竖直方向的比例大小
		 * @param pivotXType
		 *            指定pivotXValue以哪个为坐标点为中心来旋转。 Animation.ABSOLUTE,
		 *            Animation.RELATIVE_TO_SELF, 或者
		 *            Animation.RELATIVE_TO_PARENT这三个其中之一。
		 * @param pivotXValue
		 *            正在伸缩的对象的点的x坐标,指定为绝对数,并且0是左边缘(当对象改变尺寸的时候,点保持不变。)
		 *            如果pivotXType是
		 *            Animation.ABSOLUTE,这个值既可以是绝对数,也可以为百分数(1.0位100%)
		 * 
		 * @param pivotYType
		 *            指定pivotYValue以哪个为坐标点为中心来旋转。 Animation.ABSOLUTE,
		 *            Animation.RELATIVE_TO_SELF, 或者
		 *            Animation.RELATIVE_TO_PARENT这三个其中之一。
		 * @param pivotYValue
		 *            正在伸缩的对象的点的y坐标,指定为绝对数,并且0是左边缘(当对象改变尺寸的时候,点保持不变。)
		 *            如果pivotYType是
		 *            Animation.ABSOLUTE,这个值既可以是绝对数,也可以为百分数(1.0位100%)
		 */
		ScaleAnimation localScaleAnimation = new ScaleAnimation(
				this.fromXScale, this.toXScale, this.fromYScale, this.toYScale,
				Animation.RELATIVE_TO_SELF, 0.5F, Animation.RELATIVE_TO_SELF,
				0.5F);
		// 动画执行完成后,是否停留在执行完的状态
		localScaleAnimation.setFillAfter(true);
		// 在动画开始的地方速率比较慢,然后开始加速
		localScaleAnimation.setInterpolator(new AccelerateInterpolator());
		// 设置动画持续时间
		localScaleAnimation.setDuration(this.duration);
		return localScaleAnimation;
	}

}


因为之前的一篇文章已经写过了变大效果,所以这次便不详细叙述,你可以直接查看这篇文章。 http://blog.csdn.net/harryweasley/article/details/46678315图片获得焦点变大并显示在最前方,覆盖后面的图片


2.变大后,怎么让item完全显示出来,而不是被gridview的边缘挡住。


我都都知道,gridview中的item是靠着其边缘的,那么在代码中,将边缘的item变大后,便会出现显示不完全的现象。如图所示:







为了避免这样的情况发生,我在item的布局中,RelativeLayout中又加入了一个RelativeLayout,里面的RelativeLayout用了margin变量,保证内容和父控件有一定的距离。如下所示:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" >

    <RelativeLayout
        android:layout_width="@dimen/app_item_width"
        android:layout_height="@dimen/app_item_height"
        android:layout_margin="13dp"
        android:background="@drawable/background_selector2" >

        <ImageView
            android:id="@+id/app_icon"
            android:layout_width="@dimen/detail_left"
            android:layout_height="@dimen/detail_left"
            android:layout_alignParentLeft="true"
            android:layout_centerVertical="true"
            android:layout_marginLeft="30dp"
            android:src="@drawable/ic_launcher" />

        <RelativeLayout
            android:layout_width="wrap_content"
            android:layout_height="@dimen/detail_left"
            android:layout_alignBottom="@id/app_icon"
            android:layout_alignTop="@id/app_icon"
            android:layout_marginLeft="12dp"
            android:layout_toRightOf="@id/app_icon" >

            <TextView
                android:id="@+id/app_name"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentTop="true"
                android:gravity="top"
                android:text="应用名称"
                android:textColor="@color/white"
                android:textSize="@dimen/text_item_app_name" />



            <TextView
                android:id="@+id/app_size"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentBottom="true"
                android:layout_below="@id/app_name"
                android:gravity="bottom"
                android:text="13M"
                android:textColor="@color/text_search"
                android:textSize="@dimen/text_search_game" />

            <TextView
                android:id="@+id/app_count"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentBottom="true"
                android:layout_below="@id/app_name"
                android:layout_marginLeft="20dp"
                android:layout_toRightOf="@id/app_size"
                android:gravity="bottom"
                android:text="100次"
                android:textColor="@color/text_search"
                android:textSize="@dimen/text_search_game" />
        </RelativeLayout>
    </RelativeLayout>

</RelativeLayout>




3.怎么每次进入gridview当前item变大。即解决setOnItemSelectedListener不响应的方法。


这个应该是最难点了的,我花了很长的时间来研究它,最终找到了一个还算可以的方法,在这里写一下。


因为我的放大效果是在setOnItemSelectedListener方法里,来进行调用的,但是,当我实测的时候,发现setOnItemSelectedListener这个方法在第一次进入的时候,有时候会 不执行,有时候又会去执行,我也找到了他不执行的规律,但是,却很难去具体研究,可能是android内部机构的问题吧。


这样就会出现问题,如果我只是在setOnItemSelectedListener这个方法里来判断是否放大的话,那么有时候item是不会放大的,这显然是不对的。为了解决这个问题,我引入了setOnFocusChangeListener这个方法,来监gridview听焦点状态改变。经过测试,我知道了,不管怎么进入和出去gridview,setOnFocusChangeListener是一定会执行的,而且是先于setOnItemSelectedListener这个方法。

我的想法是,先进行setOnItemSelectedListener来将item变大,如果这个方法没有执行,再在setOnFocusChangeListener,将item变大,为了等待setOnItemSelectedListener是否执行的消息isSelect,在setOnFocusChangeListener开启子线程,等待isSelect,如果isSelect为true,则不执行本方法里appWallBaseAdapter.notifyDataSetChanged();如果为false则执行。


setOnFocusChangeListener代码如下所示,

appGrid.setOnFocusChangeListener(new OnFocusChangeListener() {

			@Override
			public void onFocusChange(View v, boolean hasFocus) {
				if (hasFocus) {
					// 如果获取到焦点
					// 开启线程等待50ms,看是否setOnItemSelectedListener执行,没有执行则执行此方法
					new Thread(run).start();

				} else {
					last = selected;
					Log.i("tag", last + "onfoceus 出来的这里是几..............");
					selected = -1;
					appWallBaseAdapter.notifyDataSetChanged();
					isSelect = false;
				}
			}
		});


开启线程等待50ms。

Runnable run = new Runnable() {

		@Override
		public void run() {
			try {
				Thread.sleep(50);
				handler.sendEmptyMessage(0);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	};
	Handler handler = new Handler() {
		public void handleMessage(android.os.Message msg) {
			if (isSelect) {
				isSelect = false;
			} else {
				// 如果是第一次进入该gridView,则进入第一个item,如果不是第一次进去,则选择上次出来的item
				if (last == -1) {
					selected = 0;
				} else {
					selected = last;
				}

				last = -1;
				appWallBaseAdapter.notifyDataSetChanged();
			}
		};
	};


setOnItemSelectedListener方法如下所示,如果执行了则将isSelect置为true。

appGrid.setOnItemSelectedListener(new OnItemSelectedListener() {

			@Override
			public void onItemSelected(AdapterView<?> parent, View view,
					int position, long id) {
				Log.i("tag", "OnItemSelectedListener执行了");
				isSelect = true;
				last = selected;
				selected = position;
				appWallBaseAdapter.notifyDataSetChanged();
				appGrid.smoothScrollToPositionFromTop(position, 300);

			}

			@Override
			public void onNothingSelected(AdapterView<?> parent) {
				Log.i("tag", "");
			}
		});




现在整个项目便大功告成了,MainActivity里的所有代码如下所示:

package com.example.test;

import java.util.ArrayList;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnFocusChangeListener;
import android.view.ViewGroup;
import android.view.Window;
import android.view.animation.Animation;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

public class MainActivity extends Activity {
	/**
	 * 各种应用的gridView
	 */
	private GridView appGrid;
	/**
	 * 界面左边的各种信息listView
	 * 
	 */
	private ListView appWallListView;
	/**
	 * 自定义动画类
	 */
	ScaleAnimEffect animEffect = new ScaleAnimEffect();
	/**
	 * 应用墙的适配器
	 */
	AppWallBaseAdapter appWallBaseAdapter;
	/**
	 * 当前选择的item位置
	 */
	int selected = -1;
	/**
	 * 上一次选择的item位置
	 */
	int last = -1;
	/**
	 * 是否onItemSelected方法执行了
	 */
	boolean isSelect = false;
	/**
	 * 界面左边上下的箭头图片
	 */
	ImageView top_image, bottom_iamge;

	ArrayList<String> list = new ArrayList<String>();

	@Override
	protected void onCreate(Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.activity_app_wall);
		top_image = (ImageView) findViewById(R.id.top);
		bottom_iamge = (ImageView) findViewById(R.id.bottom);
		appGrid = (GridView) findViewById(R.id.app_wall);
		appGridShow();
		appWallListViewShow();
		appWallListView.requestFocus();

	}

	/**
	 * 应用墙应用展示界面
	 */
	private void appGridShow() {
		appWallBaseAdapter = new AppWallBaseAdapter(this);
		appGrid.setAdapter(appWallBaseAdapter);
		appGrid.setOnItemSelectedListener(new OnItemSelectedListener() {

			@Override
			public void onItemSelected(AdapterView<?> parent, View view,
					int position, long id) {
				Log.i("tag", "OnItemSelectedListener执行了");
				isSelect = true;
				last = selected;
				selected = position;
				appWallBaseAdapter.notifyDataSetChanged();
				appGrid.smoothScrollToPositionFromTop(position, 300);

			}

			@Override
			public void onNothingSelected(AdapterView<?> parent) {
				Log.i("tag", "");
			}
		});

		appGrid.setOnFocusChangeListener(new OnFocusChangeListener() {

			@Override
			public void onFocusChange(View v, boolean hasFocus) {
				if (hasFocus) {
					// 如果获取到焦点
					// 开启线程等待50ms,看是否setOnItemSelectedListener执行,没有执行则执行此方法
					new Thread(run).start();

				} else {
					last = selected;
					Log.i("tag", last + "onfoceus 出来的这里是几..............");
					selected = -1;
					appWallBaseAdapter.notifyDataSetChanged();
					isSelect = false;
				}
			}
		});
	}

	Runnable run = new Runnable() {

		@Override
		public void run() {
			try {
				Thread.sleep(50);
				handler.sendEmptyMessage(0);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	};
	Handler handler = new Handler() {
		public void handleMessage(android.os.Message msg) {
			if (isSelect) {
				isSelect = false;
			} else {
				// 如果是第一次进入该gridView,则进入第一个item,如果不是第一次进去,则选择上次出来的item
				if (last == -1) {
					selected = 0;
				} else {
					selected = last;
				}

				last = -1;
				appWallBaseAdapter.notifyDataSetChanged();
			}
		};
	};

	class AppWallBaseAdapter extends BaseAdapter {
		private Context context;

		public AppWallBaseAdapter(Context context) {
			this.context = context;
		}

		@Override
		public int getCount() {

			return 13;
		}

		@Override
		public Object getItem(int position) {

			return null;
		}

		@Override
		public long getItemId(int position) {

			return 0;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			ViewHolder holder;
			if (convertView == null) {
				convertView = LayoutInflater.from(context).inflate(
						R.layout.item_app_wall2, parent, false);
				holder = new ViewHolder();
				holder.icon = (ImageView) convertView
						.findViewById(R.id.app_icon);
				holder.name = (TextView) convertView
						.findViewById(R.id.app_name);
				holder.size = (TextView) convertView
						.findViewById(R.id.app_size);
				holder.count = (TextView) convertView
						.findViewById(R.id.app_count);
				convertView.setTag(holder);
			} else {
				holder = (ViewHolder) convertView.getTag();
			}
			if (selected == position) {
				// 如果选中的是当前item,则将当前item变大。
				convertView.bringToFront();
				animEffect.setAttributs(1.0F, 1.0366F, 1.0F, 1.0366F, 100L);
				Animation localAnimation = animEffect.createAnimation();
				convertView.startAnimation(localAnimation);
			}
			if (last == position) {
				// 将上一个选中的item恢复原样。
				animEffect.setAttributs(1.0366F, 1.0F, 1.0366F, 1.0F, 0L);
				convertView.startAnimation(animEffect.createAnimation());
			}
			return convertView;
		}

		class ViewHolder {
			ImageView icon, grade;
			TextView name, size, count;
		}

	}

	/**
	 * 应用墙界面左边展示
	 */
	private void appWallListViewShow() {
		for (int i = 0; i < 10; i++) {
			list.add("网" + i);
		}

		if (list.size() <= 10) {
			bottom_iamge.setVisibility(View.INVISIBLE);
		}

		appWallListView = (ListView) findViewById(R.id.app_wall_listview);
		appWallListView.setAdapter(new AppWallListBaseAdapter(this, list));

		appWallListView.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id) {
			}
		});

		appWallListView.setOnItemSelectedListener(new OnItemSelectedListener() {

			@Override
			public void onItemSelected(AdapterView<?> parent, View view,
					int position, long id) {
				if (position > 4) {
					top_image.setVisibility(View.VISIBLE);
				}

				if (position == list.size() - 1) {
					bottom_iamge.setVisibility(View.INVISIBLE);
				}

				if (position == 0) {
					top_image.setVisibility(View.INVISIBLE);
				}

				if (position < list.size() - 5) {
					bottom_iamge.setVisibility(View.VISIBLE);
				}

			}

			@Override
			public void onNothingSelected(AdapterView<?> parent) {
			}
		});

	}

}



activity_app_wall.xml文件如下所示:


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/main_backgrand" >

    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="@dimen/detail_left"
        android:layout_marginTop="@dimen/programa_top"
        android:text="最新"
        android:textColor="@color/white"
        android:textSize="@dimen/text_detail_app_name" />


    <ImageView
        android:id="@+id/top"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/text"
        android:layout_marginLeft="92dp"
        android:layout_marginTop="@dimen/detail_icon_top"
        android:visibility="invisible"
        android:src="@drawable/top_focused" />

    <ImageView
        android:id="@+id/bottom"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="@dimen/detail_left"
        android:layout_marginLeft="92dp"
        android:src="@drawable/bottom_focused" />

    <ListView
        android:id="@+id/app_wall_listview"
        android:layout_width="108dp"
        android:layout_height="wrap_content"
        android:layout_above="@id/bottom"
        android:layout_below="@id/top"
        android:layout_marginBottom="42dp"
        android:layout_marginLeft="49dp"
        android:layout_marginTop="42dp"
        android:divider="@android:color/transparent"
        android:nextFocusDown="@id/app_wall_listview"
        android:nextFocusUp="@id/app_wall_listview"
        android:scrollbars="none" >
    </ListView>

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="@dimen/detail_recommend_icon"
        android:layout_marginLeft="57dp"
        android:layout_marginRight="@dimen/programa_gridview_left"
        android:layout_marginTop="100dp"
        android:layout_toRightOf="@id/app_wall_listview" >

        <GridView
            android:id="@+id/app_wall"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:listSelector="@android:color/transparent"
            android:numColumns="3"
            android:scrollbars="none"
            android:verticalSpacing="@dimen/search_game_left" >
        </GridView>
    </RelativeLayout>

</RelativeLayout>





其实在做本项目的时候,还有一个逻辑问题,就是当前选中的item放大,之前的item恢复原样,这个逻辑也是在代码里进行了注释和体现,希望大家注意。


关于这行代码,convertView = LayoutInflater.from(context).inflate(R.layout.item_app_wall2, parent, false);如果你不不是很懂的话,建议你看这篇文章,我觉得是很重要 的

http://blog.csdn.net/harryweasley/article/details/46646773 

LayoutInflater.inflate方法解析


本项目的完整代码链接:http://download.csdn.net/detail/harryweasley/8886349

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值