[补充]可以在主线程控制,特别注意
scrollView3.postDelayed(new Runnable() {
@Override
public void run() {
scrollView3.scrollTo(0, num * scrollItemHeight);
}
}, 500);
if (mScrollX != x || mScrollY != y) 这个判断语句有没有通过是关键所在. 这也间接说明了, 在Activity 没初始化完成, ScrollView 对象获取的一些信息是不准确的, 直接导致了scrollTo() 方法无效.
package com.exmyth.ui.adapter; import java.util.ArrayList; import java.util.List; import android.content.Context; import android.graphics.Color; import android.os.Handler; import android.os.Message; import android.util.TypedValue; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnTouchListener; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.LinearLayout.LayoutParams; import android.widget.ScrollView; import android.widget.TextSwitcher; import android.widget.TextView; import com.sunskyjun.fwproject.R; import com.sunskyjun.fwproject.adapter.PhotoScrollAdapter; import com.sunskyjun.fwproject.ui.model.Entry; import com.sunskyjun.fwproject.ui.model.ProductItem; import com.sunskyjun.fwproject.ui.view.ObservableScrollView; import com.sunskyjun.fwproject.ui.view.ObservableScrollView.OnScrollChangeListener; import com.sunskyjun.fwproject.ui.view.ObservableScrollView.OnScrollStopListener; import com.sunskyjun.fwproject.widgts.viewflow.CircleFlowIndicator; import com.sunskyjun.fwproject.widgts.viewflow.ViewFlow; public class ProductItemAdapter extends BaseAdapter{ public class ScrollViewTouchListener implements OnTouchListener { private int lastY = 0; private int touchEventId = 16; private ObservableScrollView scrollView3; private int position; private TextView txtValue; public ScrollViewTouchListener(ObservableScrollView scrollView3, int position, TextView txtValue) { super(); this.scrollView3 = scrollView3; this.position = position; this.txtValue = txtValue; } private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); View scroller = (View) msg.obj; if (msg.what == touchEventId) { if (lastY == scroller.getScrollY()) { handleStop(scroller); } else { handler.sendMessageDelayed(handler.obtainMessage( touchEventId, scroller), 5); lastY = scroller.getScrollY(); } } } }; public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_UP) { handler.sendMessageDelayed( handler.obtainMessage(touchEventId, v), 5); } return false; } private void handleStop(Object view) { ScrollView scroller = (ScrollView) view; int scrollY = scroller.getScrollY(); final int num = (scrollY + scrollItemHeight / 2)/ scrollItemHeight; entryList.get(position - 1).setIndex(num); txtValue.setText(entryList.get(position-1).getValue()[num]); // scrollView3.scrollTo(0, num * scrollItemHeight); scrollView3.postDelayed(new Runnable() { @Override public void run() { scrollView3.scrollTo(0, num * scrollItemHeight); } }, 500); } } public class ScrollStopListener implements OnScrollStopListener { private TextView txtValue; private int position; private ObservableScrollView scrollView3; public ScrollStopListener(ObservableScrollView scrollView3,TextView txtValue, int position) { this.scrollView3 = scrollView3; this.txtValue = txtValue; this.position = position; } @Override public void onScrollStop(ObservableScrollView observableScrollView) { int num = (scrollView3.getScrollY() + scrollItemHeight / 2) / scrollItemHeight; scrollView3.scrollTo(0, num * scrollItemHeight); entryList.get(position - 1).setIndex(num); txtValue.setText(entryList.get(position-1).getValue()[num]); } } public class ScrollChangeListener implements OnScrollChangeListener { private ObservableScrollView scrollView1; private ObservableScrollView scrollView2; public ScrollChangeListener(ObservableScrollView scrollView1,ObservableScrollView scrollView2) { super(); this.scrollView1 = scrollView1; this.scrollView2 = scrollView2; } @Override public void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldx, int oldy) { this.scrollView1.scrollTo(x, y); this.scrollView2.scrollTo(x, y); } } public class OnItemClickListener implements OnClickListener { private LinearLayout lytOption; private ImageView imgTrigger; public OnItemClickListener(LinearLayout lytOption, ImageView imgTrigger) { super(); this.lytOption = lytOption; this.imgTrigger = imgTrigger; } @Override public void onClick(View v) { if(View.VISIBLE == this.lytOption.getVisibility()){ this.lytOption.setVisibility(View.GONE); this.imgTrigger.setImageResource(R.drawable.fragment_product_detail_entry_combo_collapse); } else{ this.lytOption.setVisibility(View.VISIBLE); this.imgTrigger.setImageResource(R.drawable.fragment_product_detail_entry_combo_expand); } } } private Context mContext; private LayoutInflater mInflater; private List<Entry> entryList = new ArrayList<Entry>(); public ProductItem productItem = new ProductItem(); private final int VIEW_TYPE_SUMMARY = 0; private final int VIEW_TYPE_COMBO = 1; private final int VIEW_TYPE_TEXT = 2; // private OnComboClickListener onComboClickListener; private int scrollItemHeight = 70; public ScrollView loadDetailLayout; public ProductItemAdapter(Context mContext) { super(); this.mContext = mContext; this.mInflater = LayoutInflater.from(mContext); } public ProductItemAdapter(Context mContext,List<Entry> entryList) { super(); this.mContext = mContext; this.mInflater = LayoutInflater.from(mContext); this.entryList = entryList; } public ProductItemAdapter(Context mContext, ProductItem productItem) { super(); this.mContext = mContext; this.mInflater = LayoutInflater.from(mContext); this.productItem = productItem; this.entryList = productItem.getParams(); } public ProductItemAdapter(Context mContext, List<Entry> entryList, int scrollItemHeight) { super(); this.mContext = mContext; this.mInflater = LayoutInflater.from(mContext); this.entryList = entryList; this.scrollItemHeight = scrollItemHeight; } @Override public int getCount() { return (entryList.size()+1); } @Override public Object getItem(int position) { if(0 == position){ return productItem; } return entryList.get(position - 1); } @Override public long getItemId(int position) { return position; } @Override public boolean isEnabled(int position) { if (0 == position) { return false; } if(Entry.PARAM_TYPE_TEXT.equals(entryList.get(position - 1).getType())){ return false; } return super.isEnabled(position); } @Override public int getViewTypeCount() { return 3; } @Override public int getItemViewType(int position) { if(0 == position){ return VIEW_TYPE_SUMMARY; } if(Entry.PARAM_TYPE_COMBO.equals(entryList.get(position - 1).getType())){ return VIEW_TYPE_COMBO; } return VIEW_TYPE_TEXT; } @Override public View getView(int position, View convertView, ViewGroup parent) { View view; if(VIEW_TYPE_SUMMARY == getItemViewType(position)){ view = getSummaryConvertView(position, convertView, parent); } else if(VIEW_TYPE_COMBO == getItemViewType(position)){ view = getComboConvertView(position, convertView, parent); } else{ view = getTextConvertView(position, convertView, parent); } return view; } private View getSummaryConvertView(int position, View convertView, ViewGroup parent) { View view = convertView; SummaryViewHolder holder = null; if (null == convertView) { view = mInflater.inflate(R.layout.fragment_product_detail_entry_summary, null); holder = new SummaryViewHolder(); holder.txtProductName = (TextView) view.findViewById(R.id.fragment_product_detail_entry_summary_productName); holder.txtStandard = (TextView) view.findViewById(R.id.fragment_product_detail_entry_summary_standard); holder.txtFeatureDesc = (TextView) view.findViewById(R.id.fragment_product_detail_entry_summary_featureDesc); holder.viewFlow = (ViewFlow) view.findViewById(R.id.fragment_product_detail_entry_summary_viewflow); holder.viewFlow.setOnScrollListener(new ViewFlow.ScrollListener(){ @Override public void onScrolling() { loadDetailLayout.requestDisallowInterceptTouchEvent(true); } @Override public void scrollEnd() { loadDetailLayout.requestDisallowInterceptTouchEvent(false); }}); holder.circleFlowIndicator = (CircleFlowIndicator) view .findViewById(R.id.fragment_product_detail_entry_summary_viewflowindic); view.setTag(holder); } else { holder = (SummaryViewHolder)view.getTag(); } holder.txtProductName.setText(productItem.getProductName()); holder.txtStandard.setText(productItem.getProductName()); holder.txtFeatureDesc.setText(productItem.getFeatureDesc()); if(null != productItem.getProductUrls() && 0 < productItem.getProductUrls().length){ PhotoScrollAdapter photoscrollAdapter = new PhotoScrollAdapter(mContext,productItem.getProductUrls(), holder.viewFlow); photoscrollAdapter.setData(productItem.getProductUrls()); holder.viewFlow.setAdapter(photoscrollAdapter); holder.viewFlow.setFlowIndicator(holder.circleFlowIndicator); holder.viewFlow.setTimeSpan(6000); holder.viewFlow.startAutoFlowTimer(); } return view; } private View getComboConvertView(int position, View convertView, ViewGroup parent) { View view = convertView; ComboViewHolder holder = null; if (null == convertView) { view = mInflater.inflate(R.layout.fragment_product_detail_entry_combo, null); holder = new ComboViewHolder(); holder.lytItem = (FrameLayout) view.findViewById(R.id.fragment_product_detail_entry_combo_item); holder.txtName = (TextView) view.findViewById(R.id.fragment_product_detail_entry_combo_name); holder.txtValue = (TextView) view.findViewById(R.id.fragment_product_detail_entry_combo_value); holder.imgTrigger = (ImageView) view.findViewById(R.id.fragment_product_detail_entry_combo_trigger); holder.lytOption = (LinearLayout) view.findViewById(R.id.fragment_product_detail_entry_combo_option); holder.lytScrollView1 = (ObservableScrollView) view.findViewById(R.id.fragment_product_detail_entry_combo_scrollView1); holder.lytEnums1 = (LinearLayout) view.findViewById(R.id.fragment_product_detail_entry_combo_enums1); holder.lytScrollView2 = (ObservableScrollView) view.findViewById(R.id.fragment_product_detail_entry_combo_scrollView2); holder.lytEnums2 = (LinearLayout) view.findViewById(R.id.fragment_product_detail_entry_combo_enums2); holder.lytScrollView3 = (ObservableScrollView) view.findViewById(R.id.fragment_product_detail_entry_combo_scrollView3); holder.lytEnums3 = (LinearLayout) view.findViewById(R.id.fragment_product_detail_entry_combo_enums3); view.setTag(holder); } else { holder = (ComboViewHolder)view.getTag(); } Entry entry = entryList.get(position - 1); holder.txtName.setText(entry.getName()); holder.txtValue.setText(entry.getValue()[entry.getIndex()]); holder.lytEnums3.setBackgroundColor(Color.TRANSPARENT); inflateScrollView(holder.lytEnums1,holder.lytEnums2,holder.lytEnums3,entry.getValue()); holder.lytItem.setOnClickListener(new OnItemClickListener(holder.lytOption,holder.imgTrigger)); // holder.lytScrollView1.setOnScrollChangeListener(new ScrollChangeListener(holder.lytScrollView2)); // holder.lytScrollView2.setOnScrollChangeListener(new ScrollChangeListener(holder.lytScrollView1)); // ScrollStopListener stopListener1 = new ScrollStopListener(holder.lytScrollView1, holder.lytScrollView2,holder.txtValue,position); // ScrollStopListener stopListener2 = new ScrollStopListener(holder.lytScrollView2, holder.lytScrollView1,holder.txtValue,position); // holder.lytScrollView1.setOnScrollStopListener(stopListener1); // holder.lytScrollView1.setOnScrollStopListener(stopListener2); // ScrollStopListener stopListener = new ScrollStopListener(holder.lytScrollView3,holder.lytScrollView1, holder.lytScrollView2,holder.txtValue,position); holder.lytScrollView3.setOnScrollChangeListener(new ScrollChangeListener(holder.lytScrollView1,holder.lytScrollView2)); holder.lytScrollView3.scrollTo(0, entry.getIndex() * scrollItemHeight); holder.lytScrollView3.setOnTouchListener(new ScrollViewTouchListener(holder.lytScrollView3,position,holder.txtValue)); return view; } private void inflateScrollView(LinearLayout lytEnums1, LinearLayout lytEnums2, LinearLayout lytEnums3, String[] value) { LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, scrollItemHeight); lytEnums1.removeAllViews(); lytEnums2.removeAllViews(); lytEnums3.removeAllViews(); TextView blankBegin = getTextView("",14); View viewStart = new View(mContext); // viewStart.getBackground().setAlpha(0);//0~255透明度值 viewStart.setLayoutParams(param); lytEnums3.addView(viewStart); lytEnums1.addView(blankBegin); for(int i = 0; i < value.length; i++){ TextView txt1 = getTextView(value[i],14,R.color.fragment_product_detail_entry_combo_enums1,R.color.white); TextView txt2 = getTextView(value[i],16,R.color.fragment_product_detail_entry_combo_enums2,R.color.fragment_product_detail_entry_combo_enums2bg); lytEnums1.addView(txt1); lytEnums2.addView(txt2); View view = new View(mContext); // view.getBackground().setAlpha(0);//0~255透明度值 view.setLayoutParams(param); lytEnums3.addView(view); } TextView blankEnd = getTextView("",14); lytEnums1.addView(blankEnd); View viewEnd = new View(mContext); // viewEnd.getBackground().setAlpha(0);//0~255透明度值 viewEnd.setLayoutParams(param); lytEnums3.addView(viewEnd); } private TextView getTextView(String text,int size) { return this.getTextView(text, size, R.color.fragment_product_detail_entry_combo_enums1, R.color.white); } private TextView getTextView(String text,int size, int txtColorId, int bgColorId) { TextView textView = new TextView(mContext); textView.setText(text); textView.setGravity(Gravity.CENTER); textView.setTextColor(mContext.getResources().getColor(txtColorId)); textView.setBackgroundColor(mContext.getResources().getColor(bgColorId)); textView.setLayoutParams(new TextSwitcher.LayoutParams( LayoutParams.MATCH_PARENT, scrollItemHeight)); textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, size); return textView; } private View getTextConvertView(int position, View convertView,ViewGroup parent) { View view = convertView; TextViewHolder holder = null; if (null == convertView) { view = mInflater.inflate(R.layout.fragment_product_detail_entry_text, null); holder = new TextViewHolder(); holder.txtName = (TextView) view.findViewById(R.id.fragment_product_detail_entry_text_name); holder.txtValue = (TextView) view.findViewById(R.id.fragment_product_detail_entry_text_value); view.setTag(holder); } else { holder = (TextViewHolder)view.getTag(); } final Entry entry = entryList.get(position - 1); holder.txtName.setText(entry.getName()); holder.txtValue.setText(entry.getValue()[0]); return view; } public interface OnComboClickListener { public void onComboClick(); } public class TextViewHolder{ public TextView txtName; public TextView txtValue; } public class ComboViewHolder{ public LinearLayout lytEnums3; public ObservableScrollView lytScrollView3; public LinearLayout lytEnums2; public LinearLayout lytEnums1; public ObservableScrollView lytScrollView2; public ObservableScrollView lytScrollView1; public LinearLayout lytOption; public FrameLayout lytItem; public ImageView imgTrigger; public TextView txtValue; public TextView txtName; } public class SummaryViewHolder { public CircleFlowIndicator circleFlowIndicator; public ViewFlow viewFlow; public TextView txtFeatureDesc; public TextView txtStandard; public TextView txtProductName; } }
http://stackoverflow.com/questions/3738965/android-detect-when-scrollview-has-finished-scrolling-and-bouncing-back
ScrollView 用的是scroller做的滑动, 但是 scroller 被scrollView隐藏了 你无法调用 你可以直接自己写个Scrollview 代码完全copy 自带的scrollView 然后把scroller暴露出来!
可以派生的。如果(mScroller.computeScrollOffset()返回false则表示滚动结束了。
import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; import android.widget.ScrollView; public class ObservableScrollView extends ScrollView { private OnScrollChangeListener onScrollChangeListener = null; private OnScrollStopListener onScrollStopListener = null; private OnBorderListener onBorderListener = null; private boolean isBorderMonitor = false; private boolean isStart = false; public ObservableScrollView(Context context) { this(context, null); // TODO Auto-generated constructor stub } public ObservableScrollView(Context context, AttributeSet attrs) { super(context, attrs); initObservableScrollView(); // this(context, attrs, com.android.internal.R.attr.scrollViewStyle); // TODO Auto-generated constructor stub } public ObservableScrollView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initObservableScrollView(); // TODO Auto-generated constructor stub } private void initObservableScrollView() { } @Override public boolean dispatchTouchEvent(MotionEvent ev) { //requestDisallowInterceptTouchEvent(disallowIntercept); //disallowIntercept=true不让父元素拦截元素;disallowIntercept=false,没有拦截 getParent().requestDisallowInterceptTouchEvent(true); return super.dispatchTouchEvent(ev); } public void setOnScrollStopListener(OnScrollStopListener onScrollStopListener) { this.onScrollStopListener = onScrollStopListener; } public void setOnScrollChangeListener( OnScrollChangeListener onScrollChangeListener) { this.onScrollChangeListener = onScrollChangeListener; } public void setOnBorderListener(OnBorderListener onBorderListener) { this.isBorderMonitor = true; this.onBorderListener = onBorderListener; } private void onScrollFinished(){ if(null != onScrollStopListener){ onScrollStopListener.onScrollStop(this); } } private void onScrollStart(int l, int t) { if (!isStart) { isStart = true; new ScrollListener(l,t).start(); } } class ScrollListener extends Thread { int oldX, oldY; public ScrollListener(int oldx, int oldy) { this.oldX = oldx; this.oldY = oldy; } public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } while (isStart) { int newX = getScrollX(); int newY = getScrollY(); if (newX == oldX && newY == oldY) { onScrollFinished(); isStart = false; } else { oldX = newX; oldY = newY; } } } } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { onScrollStart(l,t); super.onScrollChanged(l, t, oldl, oldt); if (onScrollChangeListener != null) { onScrollChangeListener.onScrollChanged(this, l, t, oldl, oldt); } if (isBorderMonitor) { if (0 == t && null != onBorderListener) { onBorderListener.onBottom(); } else if ((getChildAt(0).getMeasuredHeight() <= t + getHeight()) && null != onBorderListener) { onBorderListener.onTop(); } } } public interface OnScrollChangeListener { public void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldx, int oldy); } public interface OnScrollStopListener { public void onScrollStop(ObservableScrollView scrollView); } /** * OnBorderListener, Called when scroll to top or bottom * * @author Myth 2013-5-22 */ public static interface OnBorderListener { /** * Called when scroll to bottom */ public void onBottom(); /** * Called when scroll to top */ public void onTop(); } public void setBorderMonitor(boolean isBorderMonitor) { this.isBorderMonitor = isBorderMonitor; } }
import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; import android.widget.ScrollView; public class ObservableScrollView extends ScrollView { private OnScrollChangeListener onScrollChangeListener = null; private OnScrollStopListener onScrollStopListener = null; private OnBorderListener onBorderListener = null; private boolean isBorderMonitor = false; private boolean isStart = false; public ObservableScrollView(Context context) { this(context, null); // TODO Auto-generated constructor stub } public ObservableScrollView(Context context, AttributeSet attrs) { super(context, attrs); initObservableScrollView(); // this(context, attrs, com.android.internal.R.attr.scrollViewStyle); // TODO Auto-generated constructor stub } public ObservableScrollView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initObservableScrollView(); // TODO Auto-generated constructor stub } private void initObservableScrollView() { } @Override public boolean dispatchTouchEvent(MotionEvent ev) { //requestDisallowInterceptTouchEvent(disallowIntercept); //disallowIntercept=true不让父元素拦截元素;disallowIntercept=false,没有拦截 getParent().requestDisallowInterceptTouchEvent(true); return super.dispatchTouchEvent(ev); } public void setOnScrollStopListener(OnScrollStopListener onScrollStopListener) { this.onScrollStopListener = onScrollStopListener; } public void setOnScrollChangeListener( OnScrollChangeListener onScrollChangeListener) { this.onScrollChangeListener = onScrollChangeListener; } public void setOnBorderListener(OnBorderListener onBorderListener) { this.isBorderMonitor = true; this.onBorderListener = onBorderListener; } @Override public boolean onTouchEvent(MotionEvent ev) { if(ev.getAction() == MotionEvent.ACTION_UP){ // 手指松开. if (null != onScrollStopListener) { onScrollStopListener.onScrollStop(this); } } return super.onTouchEvent(ev); } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); if (onScrollChangeListener != null) { onScrollChangeListener.onScrollChanged(this, l, t, oldl, oldt); } if (isBorderMonitor) { if (0 == t && null != onBorderListener) { onBorderListener.onBottom(); } else if ((getChildAt(0).getMeasuredHeight() <= t + getHeight()) && null != onBorderListener) { onBorderListener.onTop(); } } } public interface OnScrollChangeListener { public void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldx, int oldy); } public interface OnScrollStopListener { public void onScrollStop(ObservableScrollView scrollView); } /** * OnBorderListener, Called when scroll to top or bottom * * @author Myth 2013-5-22 */ public static interface OnBorderListener { /** * Called when scroll to bottom */ public void onBottom(); /** * Called when scroll to top */ public void onTop(); } public void setBorderMonitor(boolean isBorderMonitor) { this.isBorderMonitor = isBorderMonitor; } }
public class CustomScrollView extends ScrollView { private OnOverScrolledListener mOnOverScrolledListener = null; /** * @param context */ public CustomScrollView(Context context) { super(context); // TODO Auto-generated constructor stub } /** * @param context * @param attrs */ public CustomScrollView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub } /** * @param context * @param attrs * @param defStyle */ public CustomScrollView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // TODO Auto-generated constructor stub } /* (non-Javadoc) * @see android.widget.ScrollView#arrowScroll(int) */ @Override public boolean arrowScroll(int arg0) { // TODO Auto-generated method stub return super.arrowScroll(arg0); } /* (non-Javadoc) * @see android.widget.ScrollView#computeScroll() */ @Override public void computeScroll() { // TODO Auto-generated method stub super.computeScroll(); } /** * @return the mOnOverScrolledListener */ public OnOverScrolledListener getOnOverScrolledListener() { return mOnOverScrolledListener; } /** * @param mOnOverScrolledListener the mOnOverScrolledListener to set */ public void setOnOverScrolledListener(OnOverScrolledListener mOnOverScrolledListener) { this.mOnOverScrolledListener = mOnOverScrolledListener; } public interface OnOverScrolledListener{ public abstract void onOverScrolled(View view, int scrollX, int scrollY, boolean clampedX, boolean clampedY); } /* (non-Javadoc) * @see android.widget.ScrollView#onOverScrolled(int, int, boolean, boolean) */ @Override protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) { // TODO Auto-generated method stub super.onOverScrolled(scrollX, scrollY, clampedX, clampedY); if(mOnOverScrolledListener != null) { mOnOverScrolledListener.onOverScrolled(this, scrollX, scrollY, clampedX, clampedY); } Log.i("CustomScrollView", "===DBG:onOverScrolled"); } }