可伸缩悬浮搜索框

需求:

1.页面上悬浮一个搜索框,点击可伸缩

2.可以搜索上一个下一个

3.搜索标题内容

效果图:

注意点:

1.起始一个搜索小图片,终止一长条搜索框,中间用View做一个动画,这三个都是CardView

2.为了处处使用,封装了起来

3.搜索到的内容放进一个list,保存位置,点击上一个下一个滑动

4.输入框输入后自动搜索第一个

5.在特定情况下提示“没有搜索结果”,“已经是第一个了”,“已经是最后一个了”

6.分页后刷新list内容

7.搜索到的内容滑动搜索框正下方,由于recyclerView的原因,需要重写LinearLayoutManager

public class FloatSearchView {
    private Context context;
    private CardView largeLayout;
    private CardView smallLayout;
    private CardView animView;
    private RecyclerView recyclerView;
    private List<Object> list;
    private String className;
    private String attrName;

    public FloatSearchView(Context context, RecyclerView recyclerView, CardView largeLayout,
                           CardView smallLayout, CardView animView, String className, String attrName) {
        this.context = context;
        this.recyclerView = recyclerView;
        this.largeLayout = largeLayout;
        this.smallLayout = smallLayout;
        this.animView = animView;
        this.className = className;
        this.attrName = attrName;
    }

    private List<Integer> searchList;
    private int searchCursor;
    private EditText editText;
    private Toast toast = null;

    public void init() {
        list = new ArrayList<>();
        searchList = new ArrayList<>();
        editText = (EditText) largeLayout.findViewById(R.id.editText);
        ImageView close = (ImageView) largeLayout.findViewById(R.id.close);
        ImageView previous = (ImageView) largeLayout.findViewById(R.id.previous);
        ImageView next = (ImageView) largeLayout.findViewById(R.id.next);
        editText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void afterTextChanged(Editable editable) {
                if (editText.getText().toString().length() > 0) {
                    firstSearch();
                } else {
                    searchCursor = 0;
                    searchList.clear();
                }
            }
        });
        smallLayout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                searchViewLarger();
            }
        });
        close.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                searchViewSmaller();
                editText.setText("");
                searchCursor = 0;
                searchList.clear();
                hideInput();
            }
        });
        previous.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (searchList.size() == 0) {
                    checkToastResult();
                    return;
                }
                if (searchCursor - 1 >= 0) {
                    searchCursor--;
                    recyclerView.smoothScrollToPosition(searchList.get(searchCursor));
                } else {
                    if (toast != null) {
                        toast.cancel();
                    }
                    toast = Toast.makeText(context, "已经是第一个了", Toast.LENGTH_SHORT);
                    toast.show();
                }
            }
        });
        next.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (searchList.size() == 0) {
                    checkToastResult();
                    return;
                }
                if (searchCursor + 1 <= searchList.size() - 1) {
                    searchCursor++;
                    recyclerView.smoothScrollToPosition(searchList.get(searchCursor));
                } else {
                    if (toast != null) {
                        toast.cancel();
                    }
                    toast = Toast.makeText(context, "已经是最后一个了", Toast.LENGTH_SHORT);
                    toast.show();
                }
            }
        });
    }

    private void hideInput() {
        InputMethodManager manager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
        if (((Activity) context).getWindow().getAttributes().softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN) {
            if (((Activity) context).getCurrentFocus() != null)
                manager.hideSoftInputFromWindow(((Activity) context).getCurrentFocus()
                        .getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
        }
    }

    private void checkToastResult() {
        if (toast != null) {
            toast.setText("没有搜索结果");
            toast.setDuration(Toast.LENGTH_SHORT);
        } else {
            toast = Toast.makeText(context, "没有搜索结果", Toast.LENGTH_SHORT);
        }
        toast.show();
    }

    private void firstSearch() {
        searchList.clear();
        for (int i = 0; i < list.size(); i++) {
            try {
                Class<?> clazz = list.get(i).getClass();
                if (className.equals(clazz.getName())) {
                    Field field = clazz.getDeclaredField(attrName);
                    field.setAccessible(true);
                    String title = (String) field.get(list.get(i));
                    if (!TextUtils.isEmpty(title) && title.contains(editText.getText().toString())) {
                        searchList.add(i);
                    }
                }
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        if (searchList.size() == 0) {
            checkToastResult();
            return;
        }
        searchCursor = 0;
        recyclerView.smoothScrollToPosition(searchList.get(searchCursor));
    }

    private void searchViewSmaller() {
        largeLayout.setVisibility(View.INVISIBLE);
        float scaleBig = (float) largeLayout.getMeasuredWidth() / smallLayout.getMeasuredWidth();
        ObjectAnimator scaleAnim = ObjectAnimator.ofFloat(animView, "scaleX", scaleBig, 1f);
        int translateX = largeLayout.getMeasuredWidth() / 2 - smallLayout.getMeasuredWidth() / 2;
        ObjectAnimator translateAnim = ObjectAnimator.ofFloat(animView, "translationX", -translateX, 0);
        AnimatorSet animSet = new AnimatorSet();
        animSet.play(scaleAnim).with(translateAnim);
        animSet.setDuration(500);
        animSet.start();
        animSet.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {

            }

            @Override
            public void onAnimationEnd(Animator animator) {
                smallLayout.setVisibility(View.VISIBLE);
            }

            @Override
            public void onAnimationCancel(Animator animator) {

            }

            @Override
            public void onAnimationRepeat(Animator animator) {

            }
        });
    }

    private void searchViewLarger() {
        smallLayout.setVisibility(View.INVISIBLE);
        float scaleBig = (float) largeLayout.getMeasuredWidth() / smallLayout.getMeasuredWidth();
        ObjectAnimator scaleAnim = ObjectAnimator.ofFloat(animView, "scaleX", 1f, scaleBig);
        int translateX = largeLayout.getMeasuredWidth() / 2 - smallLayout.getMeasuredWidth() / 2;
        ObjectAnimator translateAnim = ObjectAnimator.ofFloat(animView, "translationX", 0, -translateX);
        AnimatorSet animSet = new AnimatorSet();
        animSet.play(scaleAnim).with(translateAnim);
        animSet.setDuration(500);
        animSet.start();
        animSet.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {

            }

            @Override
            public void onAnimationEnd(Animator animator) {
                largeLayout.setVisibility(View.VISIBLE);
            }

            @Override
            public void onAnimationCancel(Animator animator) {

            }

            @Override
            public void onAnimationRepeat(Animator animator) {

            }
        });
    }

    public void freshList(List<Object> list) {
        this.list.clear();
        this.list.addAll(list);
    }
}
public class TopLayoutManager extends LinearLayoutManager {

    public TopLayoutManager(Context context) {
        super(context);
    }

    public TopLayoutManager(Context context, int orientation, boolean reverseLayout) {
        super(context, orientation, reverseLayout);
    }

    public TopLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
        RecyclerView.SmoothScroller smoothScroller = new TopSmoothScroller(recyclerView.getContext());
        smoothScroller.setTargetPosition(position);
        startSmoothScroll(smoothScroller);
    }

    private static class TopSmoothScroller extends LinearSmoothScroller {

        TopSmoothScroller(Context context) {
            super(context);
        }

        @Override
        public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference) {
            return DensityHelp.dip2px(App.getApplication(), 138) - viewStart;
        }
    }
}

布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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="wrap_content"
    android:layout_marginTop="88dp"
    tools:showIn="@layout/study_plan_layout">

    <android.support.v7.widget.CardView
        android:id="@+id/animView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_margin="10dp"
        android:background="@color/white"
        app:cardElevation="6dp">

        <View
            android:layout_width="35dp"
            android:layout_height="44dp" />
    </android.support.v7.widget.CardView>

    <android.support.v7.widget.CardView
        android:id="@+id/smallLayout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_margin="10dp"
        app:cardElevation="6dp">

        <RelativeLayout
            android:layout_width="35dp"
            android:layout_height="44dp">

            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:src="@drawable/icon_search_pages" />
        </RelativeLayout>
    </android.support.v7.widget.CardView>

    <android.support.v7.widget.CardView
        android:id="@+id/largeLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:visibility="invisible"
        app:cardElevation="6dp">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="44dp">

            <ImageView
                android:id="@+id/close"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:layout_centerVertical="true"
                android:src="@drawable/classsearch_icon_close" />

            <ImageView
                android:id="@+id/next"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_toLeftOf="@id/close"
                android:src="@drawable/classsearch_icon_next" />

            <ImageView
                android:id="@+id/previous"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_toLeftOf="@id/next"
                android:src="@drawable/classsearch_icon_previous" />

            <EditText
                android:id="@+id/editText"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_alignBottom="@id/previous"
                android:layout_alignTop="@id/previous"
                android:layout_marginLeft="10dp"
                android:layout_toLeftOf="@id/previous"
                android:background="@drawable/search_bg"
                android:hint="输入搜索内容"
                android:paddingLeft="5dp"
                android:singleLine="true"
                android:textColor="@color/c333333"
                android:textColorHint="@color/c999999"
                android:textSize="14sp" />
        </RelativeLayout>
    </android.support.v7.widget.CardView>
</RelativeLayout>

调用

//初始化
TopLayoutManager layoutManager = new TopLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
FloatSearchView searchView = new FloatSearchiew(this, recyclerView, largeLayout, smallLayout, animView, "com.xuehu365.xuehu.model.CourseDetail", "lessonTitle"); 
searchView.init();
//刷新列表
searchView.freshList(list);
<include layout="@layout/study_plan_search_layout" />

firstSearch方法中这一段

Class<?> clazz = list.get(i).getClass();
if (className.equals(clazz.getName())) {
    Field field = clazz.getDeclaredField(attrName);
    field.setAccessible(true);
    String title = (String) field.get(list.get(i));
    if (!TextUtils.isEmpty(title) && title.contains(editText.getText().toString())) {
        searchList.add(i);
    }
}

如果实体不同,修改className,和attrName即可

高亮就不做了,adapter.notify。。

原文地址:https://www.cnblogs.com/anni-qianqian/p/8316560.html