天天看点

【Android】完美解决HorizontalScrollView和SwipeRefreshLayout放在一起报空指针的问题

这类问题如果细化到ViewPager和SwipeRefreshLayout方面,解决方法详见http://blog.csdn.net/u010386612/article/details/50548977

一般来说,HorizontalScrollView会选用一个Adapter,而且一般会用自定义的Adapter

我这里用的是我自己定义的HorizontalScrollAdapter

public abstract class BaseHorizontalAdapter
{
	private HorizontalScrollMenu mHorizontalScrollMenu;
	
	public abstract List<String> getMenuItems();

	public abstract List<View> getContentViews();
	
	public abstract void onPageChanged(int position,boolean visitStatus);
	
	public void setHorizontalScrollMenu(HorizontalScrollMenu horizontalScrollMenu)
	{
		mHorizontalScrollMenu=horizontalScrollMenu;
	}
	
	public void notifyDataSetChanged()
	{
		mHorizontalScrollMenu.notifyDataSetChanged(this);
	}
}
           

自定义的HorizontalScrollviewMenu,附上代码

public class HorizontalScrollMenu extends LinearLayout
{
	private BaseHorizontalAdapter mAdapter;
	private RadioGroup rg_items;
	private List<RadioButton> rb_items = new ArrayList<RadioButton>();
	private HorizontalViewPager vp_content;
	private Context mContext;
	private ColorStateList mColors;
	private int mBackgroundResId;
	private int mPaddingLeft = 20;
	private int mPaddingTop = 20;
	private int mPaddingRight = 20;
	private int mPaddingBottom = 20;
	private HorizontalScrollView hsv_menu;
	private boolean[] mVisitStatus; // 菜单访问状态
	private List<String> mItems; // 菜单名
	private List<View> mPagers; // 内容页
	private boolean mSwiped = true; // 是否可滑动

	public HorizontalScrollMenu(Context context)
	{
		this(context, null);
		// TODO Auto-generated constructor stub
	}

	public HorizontalScrollMenu(Context context, AttributeSet attrs)
	{
		this(context, attrs, 0);
		// TODO Auto-generated constructor stub
	}

	public HorizontalScrollMenu(Context context, AttributeSet attrs,
			int defStyle)
	{
		super(context, attrs, defStyle);
		// TODO Auto-generated constructor stub
		mContext = context;
		View v = LayoutInflater.from(context).inflate(
				R.layout.view_horizontal_scroll_menu, this, true);
		rg_items = (RadioGroup) v.findViewById(R.id.rg_items);
		vp_content = (HorizontalViewPager) v.findViewById(R.id.vp_content);
		
		mColors = getResources().getColorStateList(
				R.drawable.selector_menu_item_text);
		hsv_menu = (HorizontalScrollView) v.findViewById(R.id.hsv_menu);
		mBackgroundResId = R.drawable.bg_rb_checked;
	}

	public void setAdapter(BaseHorizontalAdapter adapter)
	{
		if (null != adapter)
		{
			adapter.setHorizontalScrollMenu(this);
			mAdapter = adapter;
			initView(adapter);
		}
	}

	/**
	 * 初始化视图
	 * 
	 * @param adapter
	 */
	private void initView(BaseHorizontalAdapter adapter)
	{
		if (null == adapter)
		{
			return;
		}
		mItems = mAdapter.getMenuItems();
		mVisitStatus = new boolean[mItems.size()];
		initMenuItems(mItems);
		mPagers = mAdapter.getContentViews();
		initContentViews(mPagers);
	}

	/**
	 * 当数据集改变通知视图重绘
	 * 
	 * @param adapter
	 */
	public void notifyDataSetChanged(BaseHorizontalAdapter adapter)
	{
		rg_items.removeAllViews();
		rb_items.clear();
		initView(adapter);
	}

	/**
	 * 初始化菜单项
	 * 
	 * @param items
	 */
	@SuppressLint("InflateParams")
	private void initMenuItems(List<String> items)
	{
		if (null != items && 0 != items.size())
		{
			rg_items.setOnCheckedChangeListener(mItemListener);
			for (String str : items)
			{
				RadioButton rb_item = (RadioButton) LayoutInflater.from(
						mContext).inflate(R.layout.view_horizontal_scroll_menu_item, null);
				rb_item.setTextColor(mColors);
				rb_item.setText(str);
				rb_item.setTextSize(16);
				rb_item.setGravity(Gravity.CENTER);
				rb_item.setPadding(mPaddingLeft, mPaddingTop, mPaddingRight,
						mPaddingBottom);
				rg_items.addView(rb_item);
				rb_items.add(rb_item);
			}
			rb_items.get(0).setChecked(true);
		}

	}

	/**
	 * 初始化内容
	 * 
	 * @param contentViews
	 */
	private void initContentViews(List<View> contentViews)
	{
		if (null == contentViews || 0 == contentViews.size())
		{
			return;
		}
		Log.i("list", ""+contentViews.size());
		vp_content.setAdapter(new MyViewPagerAdapter(contentViews));
		vp_content.setOnPageChangeListener(mPageListener);
	}

	/**
	 * 设置颜色变化列表
	 * 
	 * @param colorListId
	 */
	public void setColorList(int colorListId)
	{
		mColors = getResources().getColorStateList(colorListId);
	}

	/**
	 * 设置菜单项状态背景
	 * 
	 * @param resId
	 */
	public void setCheckedBackground(int resId)
	{
		mBackgroundResId = resId;
	}

	/**
	 * 菜单项切换监听器
	 */
	private OnCheckedChangeListener mItemListener = new OnCheckedChangeListener()
	{

		@Override
		public void onCheckedChanged(RadioGroup group, int checkedId)
		{
			// TODO Auto-generated method stub
			RadioButton btn = (RadioButton) group.findViewById(checkedId);
			setMenuItemsNullBackground();
			btn.setBackgroundResource(mBackgroundResId);
			btn.setPadding(mPaddingLeft, mPaddingTop, mPaddingRight,
					mPaddingBottom);
			int position = 0;
			for (int i = 0; i < rb_items.size(); i++)
			{
				if (rb_items.get(i) == btn)
				{
					position = i;
				}
			}
			vp_content.setCurrentItem(position, mSwiped);
			moveItemToCenter(btn);
			if (mVisitStatus.length >= position + 1) {
				mAdapter.onPageChanged(position, mVisitStatus[position]);
				mVisitStatus[position] = true;
			}
		}

	};

	/**
	 * 内容页切换监听器
	 */
	private OnPageChangeListener mPageListener = new OnPageChangeListener()
	{

		@Override
		public void onPageSelected(int arg0)
		{
			// TODO Auto-generated method stub
			rb_items.get(arg0).setChecked(true);
		}

		@Override
		public void onPageScrolled(int arg0, float arg1, int arg2)
		{
			// TODO Auto-generated method stub

		}

		@Override
		public void onPageScrollStateChanged(int state)
		{

		}
	};

	/**
	 * 将菜单项尽量移至中央位置
	 * 
	 * @param rb
	 */
	private void moveItemToCenter(RadioButton rb)
	{
		DisplayMetrics dm = getResources().getDisplayMetrics();
		int screenWidth = dm.widthPixels;
		int[] locations = new int[2];
		rb.getLocationInWindow(locations);
		int rbWidth = rb.getWidth();
		hsv_menu.smoothScrollBy((locations[0] + rbWidth / 2 - screenWidth / 2),
				0);
	}

	/**
	 * 设置所有菜单项的背景为空
	 */
	private void setMenuItemsNullBackground()
	{
		if (null != rg_items)
			for (int i = 0; i < rg_items.getChildCount(); i++)
			{
				View v = rg_items.getChildAt(i);
				v.setBackgroundResource(android.R.color.transparent);
			}
	}

	public void setMenuItemPaddingLeft(int paddingLeft)
	{
		mPaddingLeft = paddingLeft;
	}

	public void setMenuItemPaddingTop(int paddingTop)
	{
		mPaddingTop = paddingTop;
	}

	public void setMenuItemPaddingRight(int paddingRight)
	{
		mPaddingRight = paddingRight;
	}

	public void setMenuItemPaddingBottom(int paddingBottom)
	{
		mPaddingBottom = paddingBottom;
	}

	/**
	 * 视图页的适配器
	 * 
	 * @author Administrator
	 * 
	 */
	static class MyViewPagerAdapter extends PagerAdapter
	{
		private List<View> mViews;

		public MyViewPagerAdapter(List<View> views)
		{
			// TODO Auto-generated constructor stub
			mViews = views;
		}

		@Override
		public int getCount()
		{
			// TODO Auto-generated method stub
			return mViews.size();
		}

		@Override
		public boolean isViewFromObject(View arg0, Object arg1)
		{
			// TODO Auto-generated method stub
			return arg0 == arg1;
		}

		@Override
		public void destroyItem(ViewGroup container, int position, Object object)
		{
			// TODO Auto-generated method stub
			container.removeView(mViews.get(position));
		}

		@Override
		public Object instantiateItem(ViewGroup container, int position)
		{
			// TODO Auto-generated method stub
			container.addView(mViews.get(position));
			return mViews.get(position);
		}
	}

	public void setSwiped(boolean swiped)
	{
		mSwiped = swiped;
		vp_content.setSwiped(swiped);
	}

}
           

显然,onPagedChanged方法用于在HorizontalScrollMenu界面切换的时候调用。一般来讲,为了美观,会在切换(也就是onPageChanged)的时候设置SwipeRefreshLayout的小圆圈开始加载。但是事实上会报空指针,而且会发现空指针居然报在HorizontalMenu中调用Adapter处。

事实上问题所在就是滑动冲突。如果想要开始加载,常用的办法都是新开一个线程然后设置开始加载

//开始刷新动画
swipeRefreshLayout.post(new Runnable() {
					
	@Override
	public void run() {
		swipeRefreshLayout.setRefreshing(true);
		onRefreshListener.onRefresh();
	}
});
           

解决方法:在onPageChanged中使用handler发消息,然后在接收消息之后开始刷新动画。如果在onPageChanged中刷新动画,会因为滑动冲突报空指针

(注:事实上,在界面初始化的时候,也会调用一次onPageChanged)