Android下的仿iOS搜索 - SearchBar

文/BlackSwift(简书作者)
原文链接:http://www.jianshu.com/p/a27881f8564a
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

本文主要介绍仿iOS的searchview实现,难点主要有两个

  1. Cancel按钮的动画
  2. 用RxJava,Retrofit,Edittext进行网络请求

关键词: UISerchBar on Android , RxJava Edittext , ObjectAnimator


RxSearchView

Cancel按钮的动画

按钮动画初看以为是伸缩动画,实际上使用的是左右slide切换的动画,按钮与左边的输入框在布局上是分开的。自定义了一个ViewSwitcher,它继承于FrameLayout,内部实现了左右切换的ObjectAnimator动画,内部装了一个圆角背景,还有一个蓝色按钮

<com.github.xxxx.ViewSwitcher
    ......
    app:vsReserve="8dp">

  <!--bottom level view-->
  <TextView 
          ...
      android:text="@android:string/cancel"/>

  <!--top level view-->
  <View android:layout_width="match_parent" android:layout_height="match_parent"
      android:background="@drawable/internal_search_shape_bg_right_8"/>

</com.github.xxxx.ViewSwitcher>

app:vsReserve表示左右切换动画保留的距离,如果为0的话输入框右边的圆角背景就没了。

用RxJava,Retrofit,Edittext进行网络请求

  • 通过debounce(throttleWithTimeout)可以消除按键抖动,不用每按下一次按钮都立刻进行网络请求。debounce内部可以看成栈,下个元素的进入时间间隔小于倒计时就入栈并丢掉栈底的旧元素并重新计时,否则出栈。
  • debounce默认是开了一个非UI线程调度器,所以后面的操作符默认是在非UI线程调用的,必须在UI事件(比如progressbar)调用前设置observeOn(AndroidSchedulers.mainThread());或者手动设置调度器为主线程,它不会造成阻塞

    详情可以看Github或者stackoverflow

  • 使用switchMap与retry可以中断掉之前的请求,节约网络

各种操作符号的在线动画点这里

代码如下:

RxTextView.textChanges(mSearchbar.getEditTextSearch())
    .subscribeOn(AndroidSchedulers.mainThread())
    //delay 500ms
    //debounce and throttle will use different thread after
    .throttleWithTimeout(300, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
    .distinct()
    .filter(new Func1<CharSequence, Boolean>() {
      @UiThread @Override public Boolean call(CharSequence charSequence) {
        //void unnecessary request
        return charSequence.length() != 0;
      }
    })
    .map(new Func1<CharSequence, String>() {
      @UiThread @Override public String call(CharSequence charSequence) {
        //fit network api doc require
        return charSequence + "*";
      }
    })
    .doOnNext(new Action1<CharSequence>() {
      @UiThread @Override public void call(CharSequence charSequence) {
        progressBar.setVisibility(View.VISIBLE);
        arrayList.clear();
        adapter.notifyDataSetChanged();
      }
    })
    .observeOn(Schedulers.io())
    .switchMap(new Func1<String, Observable<List<Tag>>>() {
      @WorkerThread @Override public Observable<List<Tag>> call(String s) {
        return repo.getTags(20, s);
      }
    })
    .retry(new Func2<Integer, Throwable, Boolean>() {
      //fix InterruptedIOException bugs on Retrofit
      // when stop old search
      @WorkerThread @Override public Boolean call(Integer integer, Throwable throwable) {
        return throwable instanceof InterruptedIOException;
      }
    })
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Subscriber<List<Tag>>() {
      @Override public void onCompleted() {

      }

      @Override public void onError(Throwable e) {
        progressBar.setVisibility(View.INVISIBLE);
        e.printStackTrace();
        Toast.makeText(SearchActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
      }

      @Override public void onNext(List<Tag> tags) {
        progressBar.setVisibility(View.INVISIBLE);

        arrayList.clear();
        arrayList.addAll(tags);
        adapter.notifyDataSetChanged();
      }
    });

项目地址

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值