27
2017
09

ScrollView与SeekBar绑定实现滑动时出现小滑块的效果

这是一项挺复杂的工作

  • 重写SeekBar
  • 重写ScroView
  • 主工程
  • 布局
  • SeekBar样式修改
  • 绑定SeekBar和ScrollView
  • 监听ScrollView的滑动状态

    1,重写SeekBar

public class VerticalSeekbar extends SeekBar {
    public VerticalSeekbar(Context context) {
        super(context);
    }
    public VerticalSeekbar(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }
    public VerticalSeekbar(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(h, w, oldh, oldw);
    }
    @Override
    public synchronized void setProgress(int progress)  // it is necessary for calling setProgress on click of a button
    {
        super.setProgress(progress);
        onSizeChanged(getWidth(), getHeight(), 0, 0);
    }
    @Override
    protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(heightMeasureSpec, widthMeasureSpec);
        setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
    }
    protected void onDraw(Canvas c) {
           c.rotate(90);//旋转
        c.translate(0, -getWidth());//旋转,这两行不可去掉

        super.onDraw(c);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (!isEnabled()) {
            return false;
        }
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
            case MotionEvent.ACTION_UP:
            setProgress((int) (getMax() * event.getY() / getHeight()));
                onSizeChanged(getWidth(), getHeight(), 0, 0);
                break;
     case MotionEvent.ACTION_CANCEL:
                break;
        }
        return true;
    }

}

2,重写SccrollView

public class ObservableScrollView extends ScrollView {
    public ScrollViewListener scrollViewListener = null;
    public ObservableScrollView (Context context) {
        super(context);
    }
    public ObservableScrollView (Context context, AttributeSet attrs,
                                 int defStyle) {
        super(context, attrs, defStyle);
    }
    public interface ScrollViewListener {
        void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldx, int oldy);
    }
    public ObservableScrollView (Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public void setScrollViewListener(ScrollViewListener scrollViewListener) {
        this.scrollViewListener = scrollViewListener;
    }
   @Override
    public void onScrollChanged(int x, int y, int oldx, int oldy) {
        super.onScrollChanged(x, y, oldx, oldy);
        if (scrollViewListener != null) {
            scrollViewListener.onScrollChanged(this, x, y, oldx, oldy);
        }
    }
}

3,主工程

public class Slider_Text extends Activity {
    private TextView textView;
    private Context context=this;
    private Scroller scroller;
    private ScrollBindHelper scrollBindHelper;
    private VerticalSeekbar seekBar;
    private ObservableScrollView scrollView;
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_slider__text);
        scroller=new Scroller(context);
        textView=(TextView)findViewById(R.id.text);
        textView.setText("也许是在用这种方式告诉我,分开了就不要怀抱希望,现实,梦中都不能。\n" +
                "\n" +

                "  了,那些无处安放的情感就让它各自归位,你别来,");
         seekBar = (VerticalSeekbar) findViewById(R.id.seekbar);
         scrollView = (ObservableScrollView) findViewById(R.id.scrollView);
        scrollBindHelper=new ScrollBindHelper(seekBar,scrollView);
        scrollBindHelper.bind(seekBar,scrollView);
        scrollView.setOnTouchListener(new View.OnTouchListener() {
            private int lastY = 0;
            private int touchEventId = -9983761;
            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();
                System.out.println("scrollY"+scrollY);
                seekBar.setVisibility(View.GONE);//滑动停止后,自动隐藏seekbar
            }
        });

    }
}

4,主布局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    tools:context="io.dcloud.H5B79C397.testActivity.Slider_Text">
    <io.dcloud.H5B79C397.view.ObservableScrollView
        android:id="@+id/scrollView"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="15">
        <TextView
            android:id="@+id/text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="asdfasdfasdfff" />
    </io.dcloud.H5B79C397.view.ObservableScrollView >
    <io.dcloud.H5B79C397.view.VerticalSeekbar
        android:id="@+id/seekbar"
        android:layout_width="0dp"
        android:visibility="gone"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:progressDrawable="@drawable/seek"
        android:thumbTint="@color/green" />
</LinearLayout>

5,SeekBar样式

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@android:id/background">
        <shape>
            <corners android:radius="5dp"/>
            <solid android:color="#FFFFFF"/>
        </shape>
    </item>
    <item android:id="@android:id/secondaryProgress">
        <clip>
            <shape>
                <corners android:radius="5dp"/>
                <solid android:color="#FFFFFF"/>
            </shape>
        </clip>
    </item>
    <item android:id="@android:id/progress">
        <clip>
            <shape>
                <corners android:radius="5dp"/>
                <solid android:color="#FFFFFF" />
            </shape>
        </clip>
    </item>
</layer-list>

6,绑定SeekBar和ScrollView

public class ScrollBindHelper implements SeekBar.OnSeekBarChangeListener,ObservableScrollView.ScrollViewListener{
    private final VerticalSeekbar seekBar;
    private final ObservableScrollView scrollView;
    private final View scrollContent;
    /** * 使用静态方法来绑定逻辑,代码可读性更高。 */
    public ScrollBindHelper(VerticalSeekbar seekBar, ObservableScrollView scrollView) {
        this.seekBar = seekBar;
        this.scrollView = scrollView;
        this.scrollContent = scrollView.getChildAt(0);
       // System.out.println("scrollContent------->"+scrollView.getChildAt(0));
    }
    /*继承*/
    private boolean isUserSeeking;
    private int getContentRange() {
        seekBar.setMax(scrollContent.getHeight() - scrollView.getHeight());
        int Range=scrollView.getScrollY();
        //System.out.println("content----->"+Range);
        return Range;
    }
    private int getScrollRange() {
        System.out.println(scrollContent.getHeight() - scrollView.getHeight());
        return scrollContent.getHeight() - scrollView.getHeight();
}
    public ScrollBindHelper bind(VerticalSeekbar seekBar, ObservableScrollView scrollView) {
        //初始化工具类
        ViewUtil.init(seekBar.getContext().getApplicationContext());
        ScrollBindHelper helper = new ScrollBindHelper(seekBar, scrollView);
        seekBar.setOnSeekBarChangeListener(helper);
        scrollView.setScrollViewListener(helper);
        return helper;
    }

@Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        //当不是用户操作,也就是ScrollView的滚动隐射过来时不执行操作
        if (!fromUser) {
           // seekBar.setProgress();
            //将拖动的换百分比算成Y值,并映射到SrollView上。
            int range=getContentRange();
            scrollView.scrollTo(0, progress);
         // System.out.println("scroll----"+progress);
        }
}
    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {
        isUserSeeking = true;
        handler.clearAll();
    }
    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
        isUserSeeking = false;
        handler.reset();
    }
    /*动画*/
    public static final long DEFAULT_TIME_OUT = 10L;
    @Override
    public void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldx, int oldy) {
       showScroll();
        //用户拖动SeekBar时不触发ScrollView的回调
        if (isUserSeeking) {
            return;
        }

        //计算当前滑动位置相对于整个范围的百分比,并映射到SeekBar上
        int range = getContentRange();
        seekBar.setProgress(range != 0 ? range : 0);
        //System.out.println("seekBar------"+ range);
    }
    private static class VisibleHandler extends LastMsgHandler {
        private ScrollBindHelper helper;
        public VisibleHandler(ScrollBindHelper helper) {
            this.helper = helper;
        }
        public void reset() {
            sendMsgDelayed(DEFAULT_TIME_OUT);
        }
        @Override
        protected void handleLastMessage(Message msg) {
            helper.hideScroll();
        }
    }
    private VisibleHandler handler = new VisibleHandler(this);

    private void hideScroll() {
        seekBar.setVisibility(View.GONE);
    }
    private void showScroll() {
        seekBar.setVisibility(View.VISIBLE);
    }
}

7,工具类

public class ViewUtil  {
    private ViewUtil() {
    }

    /*视图参数*/
    private static float density;
    private static float scaledDensity;
    private static int widthPixels;
    private static int heightPixels;

    private static boolean isInit = false;

    private static void confirmInit() {
        if (!isInit) {
            throw new IllegalStateException("ViewUtil还未初始化");
        }
    }
    public static void init(Context context) {
        if (isInit) {
            return;
        }

        DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
        density = displayMetrics.density;
        scaledDensity = displayMetrics.scaledDensity;
        widthPixels = displayMetrics.widthPixels;
        heightPixels = displayMetrics.heightPixels;
        isInit = true;
    }

    public static float getDisplayMetricsDensity() {
        confirmInit();
        return density;
    }

    public static float getDisplayMetricsScaledDensity() {
        confirmInit();
        return scaledDensity;
    }

    public static int getScreenWidthPx() {
        confirmInit();
        return widthPixels;
    }

    public static int getScreenHeightPx() {
        confirmInit();
        return heightPixels;
    }

    /* 单位转换 */

    public static int dpToPx(float dpValue) {
        confirmInit();
        return (int) (dpValue * getDisplayMetricsDensity() + 0.5F);
    }

    public static int pxToDp(float pxValue) {
        confirmInit();
        return (int) (pxValue / getDisplayMetricsDensity() + 0.5F);
    }

    public static int pxToSp(float pxValue) {
        confirmInit();
        return (int) (pxValue / getDisplayMetricsScaledDensity() + 0.5f);
    }

    public static int spToPx(float spValue) {
        confirmInit();
        return (int) (spValue * getDisplayMetricsScaledDensity() + 0.5f);
    }
}

8,线程工具

public abstract class LastMsgHandler extends android.os.Handler {
    private int count = 0;

    /** * 增加Count数。你必须先调用该方法后再使用sendMessageXXX */
    public synchronized final void increaseCount() {
        count++;
    }

    public final void sendMsg() {
        sendMsgDelayed(0);
    }

    public final void sendMsgDelayed(long delay) {
        increaseCount();
        if (delay <= 0) {
            sendEmptyMessage(0);
        } else {
            sendEmptyMessageDelayed(0, delay);
        }
    }

    public synchronized final void clearAll() {
        count = 0;
        removeCallbacksAndMessages(null);
    }

    @Override
    public synchronized final void handleMessage(Message msg) {
        super.handleMessage(msg);
        count--;
        if (count < 0) {
            throw new IllegalStateException("count数异常");
        }

        if (count == 0) {
            handleLastMessage(msg);
        }
    }

    /*回调*/

    protected abstract void handleLastMessage(Message msg);
}

上图
跟着屏幕的滑动右边的小点会跟着滑动,点击滑动右边的小点可以控制屏幕的滑动,屏幕滑动结束后,小点自动隐藏

跟着屏幕的滑动右边的小点会跟着滑动,点击滑动右边的小点可以控制屏幕的滑动,屏幕滑动结束后,小点自动隐藏

上一篇:AWS快速使用 下一篇:安卓学习笔记(6)-控制ListView显示列表的数量