关于自定义视图点击冲突问题
最近在做一个android用户端的首页banner视图功能,由于时间紧迫,加上前期需求的要求,起先只需要实现能展示广告banner图片以及可以轮播的功能,前期很顺利的实现了。一段时间后,由于功能的不断完善,对这块的需求有一些改变,需要增加一个点击跳转的功能,一般如果没有仔细研究自定义视图和视图点击事件的冲突问题很容易遇到点击无效的现象。
先列出自定义视图代码:
public class BannerView extends FrameLayout {
private static final int MSG_LOOP = 1000;
private static long LOOP_INTERVAL = 5000;
private LinearLayout mLinearPosition = null;
public ViewPager mViewPager = null;
private BannerHandler mBannerHandler = null;
private List<View> viewList;
private int viewSize;
public OnItemClickListener onItemClickListener;
private int mPosition;
public interface OnItemClickListener {
void OnItemClick(int position);//参数可有可无,我只是加个给大家看一下
}
public void setOnItemClickListener(OnItemClickListener listener){
onItemClickListener = listener;
}
private static class BannerHandler extends Handler {
private WeakReference<BannerView> weakReference = null;
public BannerHandler(BannerView bannerView) {
super(Looper.getMainLooper());
this.weakReference = new WeakReference<BannerView>(bannerView);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (this.weakReference == null) {
return;
}
BannerView bannerView = this.weakReference.get();
if (bannerView == null || bannerView.mViewPager == null || bannerView.mViewPager.getAdapter() == null || bannerView.mViewPager.getAdapter().getCount() <= 0) {
// sendEmptyMessageDelayed(MSG_LOOP, LOOP_INTERVAL);
return;
}
int curPos = bannerView.mViewPager.getCurrentItem();
curPos = (curPos + 1) % bannerView.mViewPager.getAdapter().getCount();
bannerView.mViewPager.setCurrentItem(curPos);
if (hasMessages(MSG_LOOP)){
removeMessages(MSG_LOOP);
}
sendEmptyMessageDelayed(MSG_LOOP, LOOP_INTERVAL);
}
}
public BannerView(Context context) {
super(context);
init();
}
public BannerView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public void startLoop(boolean flag) {
if (flag) {
if (mBannerHandler == null) {
mBannerHandler = new BannerHandler(this);
}
mBannerHandler.sendEmptyMessageDelayed(MSG_LOOP, LOOP_INTERVAL);
} else {
if (mBannerHandler != null) {
if (mBannerHandler.hasMessages(MSG_LOOP)) {
mBannerHandler.removeMessages(MSG_LOOP);
mBannerHandler = null;
}
}
}
}
private void init() {
initViewPager();
initLinearPosition();
this.addView(mViewPager);
this.addView(mLinearPosition);
}
private void initViewPager() {
mViewPager = new ViewPager(getContext());
LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT
, ViewGroup.LayoutParams.WRAP_CONTENT);
mViewPager.setLayoutParams(layoutParams);
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
updateLinearPosition();
mPosition = position;
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
mViewPager.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.e("FFFL","ONcLICK...");
}
});
mViewPager.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
if (mBannerHandler != null) {
if (mBannerHandler.hasMessages(MSG_LOOP)) {
mBannerHandler.removeMessages(MSG_LOOP);
}
}
break;
case MotionEvent.ACTION_UP:
if (mBannerHandler != null) {
mBannerHandler.sendEmptyMessageDelayed(MSG_LOOP, LOOP_INTERVAL);
}
break;
default:
break;
}
return false;
}
});
}
private void initLinearPosition() {
mLinearPosition = new LinearLayout(getContext());
mLinearPosition.setOrientation(LinearLayout.HORIZONTAL);
LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT
, ViewGroup.LayoutParams.WRAP_CONTENT);
layoutParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
layoutParams.bottomMargin = getResources().getDimensionPixelSize(R.dimen.common_measure_9sp);
mLinearPosition.setPadding(getResources().getDimensionPixelSize(R.dimen.common_measure_9sp), 0, 0, 0);
mLinearPosition.setLayoutParams(layoutParams);
}
public void setAdapter(PagerAdapter adapter) {
mViewPager.setAdapter(adapter);
adapter.registerDataSetObserver(mDataObserver);
updateLinearPosition();
}
private DataSetObserver mDataObserver = new DataSetObserver() {
@Override
public void onChanged() {
super.onChanged();
updateLinearPosition();
}
@Override
public void onInvalidated() {
super.onInvalidated();
}
};
private void updateLinearPosition() {
if (viewList != null && viewList.size() != 0) {
if (mLinearPosition.getChildCount() != viewSize) {
int diffCnt = mLinearPosition.getChildCount() - viewSize;
boolean needAdd = diffCnt < 0;
diffCnt = Math.abs(diffCnt);
for (int i = 0; i < diffCnt; i++) {
if (needAdd) {
ImageView img = new ImageView(getContext());
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
layoutParams.rightMargin = getResources().getDimensionPixelOffset(R.dimen.common_measure_9sp);
img.setLayoutParams(layoutParams);
img.setBackgroundResource(R.drawable.shape_coner_grey);
mLinearPosition.addView(img);
} else {
mLinearPosition.removeViewAt(0);
}
}
}
int curPos = mViewPager.getCurrentItem();
for (int i = 0; i < mLinearPosition.getChildCount(); i++) {
if (i == (curPos % viewSize)) {
mLinearPosition.getChildAt(i).setBackgroundResource(R.drawable.shape_coner_red);
} else {
mLinearPosition.getChildAt(i).setBackgroundResource(R.drawable.shape_coner_grey);
}
}
}
}
public void setViewList(List<View> viewList) {
this.viewList = viewList;
if (viewList != null && viewList.size() != 0) {
viewSize = viewList.size();
BannerAdapter bannerAdapter = new BannerAdapter(viewList);
setAdapter(bannerAdapter);
bannerAdapter.setOnItemClickListener(new BannerAdapter.OnItemClickListener() {
@Override
public void OnItemClick(int position) {
if (onItemClickListener!=null){
onItemClickListener.OnItemClick(position);//此处为重点**
}
}
});
}
}
public void setTransformAnim (boolean flag){
if (flag){
mViewPager.setPageTransformer(true, new ViewPager.PageTransformer() {
private static final float MIN_SCALE = 0.75f;
@Override
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
if (position < -1)
{ // [-Infinity,-1)
// This page is way off-screen to the left.
view.setRotation(0);
} else if (position <= 1)
{ // [-1,1]
// Modify the default slide transition to shrink the page as well
if (position < 0)
{
float mRot = (20f * position);
view.setPivotX(view.getMeasuredWidth() * 0.5f);
view.setPivotY(view.getMeasuredHeight());
view.setRotation(mRot);
} else
{
float mRot = (20f * position);
view.setPivotX(view.getMeasuredWidth() * 0.5f);
view.setPivotY(view.getMeasuredHeight());
view.setRotation(mRot);
}
// Scale the page down (between MIN_SCALE and 1)
// Fade the page relative to its size.
} else
{ // (1,+Infinity]
// This page is way off-screen to the right.
view.setRotation(0);
}
}
});
}
}
public void setLoopInterval(long loopInterval) {
LOOP_INTERVAL = loopInterval;
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mBannerHandler != null){
mBannerHandler.removeMessages(MSG_LOOP);
mBannerHandler = null;
}
}
}
在activity中调用的部分:
bannerView.setOnItemClickListener(new BannerView.OnItemClickListener() {
@Override
public void OnItemClick(int position) {
if (position % 3 == 0) {
Intent intent = new Intent(getContext(), DgniosReportMainActivity.class);
intent.putExtra(ReportManageDiaActivity.TYPE_REPORT, ReportManageDiaActivity.TYPE_QUICK_SCAN);
startActivity(intent);
} else if (position % 3 == 1) {
openTeamViewer(getActivity());
} else if (position % 3 == 2) {
goWeb(“https://www.autdiy.net/goods-12.html”);
}
}
});
采用自定义回调的写法实现点击的效果。
如果纯粹的这样做还不能实现点击冲突的问题,关键点在于需要在
自定义视频的adapter中再实现一个自定义回调,
bannerAdapter.setOnItemClickListener(new BannerAdapter.OnItemClickListener() {
@Override
public void OnItemClick(int position) {
if (onItemClickListener!=null){
onItemClickListener.OnItemClick(position);//此处为重点**
}
}
});
到此处还不能解决根本冲突问题,需要在BannerAdapter中找到继承方法:instantiateItem:
public class BannerAdapter extends PagerAdapter {
private List<View> viewList;
private int size;
private final int cacheCount = 3;
private OnItemClickListener mOnItemClickListeners;
public interface OnItemClickListener {
void OnItemClick(int position);//参数可有可无,我只是加个给大家看一下
}
public void setOnItemClickListener(OnItemClickListener listener){
mOnItemClickListeners = listener;
}
public BannerAdapter(List<View> viewList) {
this.viewList = viewList;
size = viewList.size();
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
if (viewList.size() > cacheCount){
container.removeView(viewList.get(position%size));
}
}
@Override
public Object instantiateItem(ViewGroup container, final int position) {
ViewGroup parent = (ViewGroup) viewList.get(position%size).getParent();
if (parent != null) {
parent.removeView(viewList.get(position%size));
}
container.addView(viewList.get(position%size));
viewList.get(position%size).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mOnItemClickListeners!=null){
mOnItemClickListeners.OnItemClick(position%size);//此处为重点**
}
}
});
return viewList.get(position%size);
}
@Override
public int getCount() {
return Integer.MAX_VALUE;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
}
在instantiateItem()方法中实现setOnClickListener并回调给自定义视图。
到此就能解决点击和滑动不冲突。很久未写,有点生疏,希望能帮到初学者。