专栏首页恩蓝脚本ScrollView与SeekBar绑定实现滑动时出现小滑块效果

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);
}

上图

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

以上就是本文的全部内容,希望对大家的学习有所帮助。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Android自定义控件之三点循环缩放效果

    本文实例为大家分享了Android自定义控件之三点循环缩放的具体代码,供大家参考,具体内容如下

    砸漏
  • 基于Android平台实现拼图小游戏

    拼图是一款益智类经典游戏了,本游戏学习了一些前辈们的经验,整体来说讲,将图片用切图工具进行切割,监听用户手指滑动事件,当用户对凌乱的图片,在一定的时间内拼凑恢复...

    砸漏
  • android特卖列表倒计时卡顿问题的解决方法

    在Android的开发中,我们经常遇见倒计时的操作,通常使用Timer和Handler共同操作来完成。当然也可以使用Android系统控件CountDownTi...

    砸漏
  • Android自定义控件之三点循环缩放效果

    本文实例为大家分享了Android自定义控件之三点循环缩放的具体代码,供大家参考,具体内容如下

    砸漏
  • android 特卖列表倒计时卡顿问题

    在Android的开发中,我们经常遇见倒计时的操作,通常使用Timer和Handler共同操作来完成。当然也可以使用Android系统控件CountDownTi...

    xiangzhihong
  • Android自定义View实现拼图小游戏

    砸漏
  • 基于Android平台实现拼图小游戏

    拼图是一款益智类经典游戏了,本游戏学习了一些前辈们的经验,整体来说讲,将图片用切图工具进行切割,监听用户手指滑动事件,当用户对凌乱的图片,在一定的时间内拼凑恢复...

    砸漏
  • android特卖列表倒计时卡顿问题的解决方法

    在Android的开发中,我们经常遇见倒计时的操作,通常使用Timer和Handler共同操作来完成。当然也可以使用Android系统控件CountDownTi...

    砸漏
  • android RecycleView实现下拉刷新和上拉加载

    android的下拉刷新,上拉加载功能,翻页时显示从第1页开始到当前页面的内容,并且当前显示的是当前页的内容;

    砸漏
  • Android自定义GLSurfaceView

    当我们需要把同一个场景渲染到不同的Surface上时,此时系统GLSurfaceView 就不能满足需求了,所以我们需要自己创建EGL环境来实现渲染操作。 注意...

    曾大稳

扫码关注云+社区

领取腾讯云代金券