需求:
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。。