Tạo một SearchView trông giống như các nguyên tắc thiết kế vật liệu


134

Tôi hiện đang trong quá trình tìm hiểu cách chuyển đổi ứng dụng của mình sang Thiết kế Vật liệu và hiện tại tôi đang bị kẹt một chút. Tôi đã thêm Thanh công cụ và tôi đã làm cho ngăn kéo điều hướng của mình phủ lên tất cả nội dung.

Bây giờ tôi đang cố gắng tạo một tìm kiếm có thể mở rộng trông giống như trong hướng dẫn vật liệu : nhập mô tả hình ảnh ở đây

Đây là những gì tôi có ngay bây giờ và tôi không thể tìm ra cách làm cho nó giống như trên:
Tìm kiếm của tôi

Đây là menu của tôi xml:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/action_search"
        android:icon="@android:drawable/ic_menu_search"
        android:title="Search"
        app:showAsAction="always"
        app:actionViewClass="android.support.v7.widget.SearchView" />
</menu>

Điều đó hoạt động, tôi nhận được một mục menu mở rộng đến SearchView và tôi có thể lọc danh sách của mình tốt. Nó không giống bất cứ thứ gì như bức ảnh đầu tiên.

Tôi cố gắng để sử dụng MenuItemCompat.setOnActionExpandListener()trên R.id.action_searchđể tôi có thể thay đổi biểu tượng nhà của một mũi tên trở lại, nhưng điều đó dường như không làm việc. Không có gì bị sa thải trong người nghe. Ngay cả khi nó hoạt động, nó vẫn không gần với hình ảnh thứ nhất.

Làm cách nào để tạo SearchView trong thanh công cụ appcompat mới trông giống như các nguyên tắc vật liệu?


6
ứng dụng: showAsAction = "always | crashActionView"
Pavlos

Bạn có thể muốn xem câu trả lời của tôi ở đây: stackoverflow.com/a/41013994/5326551
shnizlon

Câu trả lời:


152

Nó thực sự khá dễ dàng để làm điều này, nếu bạn đang sử dụng android.support.v7thư viện.

Bước 1

Khai báo một mục menu

<item android:id="@+id/action_search"
    android:title="Search"
    android:icon="@drawable/abc_ic_search_api_mtrl_alpha"
    app:showAsAction="ifRoom|collapseActionView"
    app:actionViewClass="android.support.v7.widget.SearchView" />

Bước 2

Mở rộng AppCompatActivityvà trong onCreateOptionsMenuthiết lập SearchView.

import android.support.v7.widget.SearchView;

...

public class YourActivity extends AppCompatActivity {

    ...

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_home, menu);
        // Retrieve the SearchView and plug it into SearchManager
        final SearchView searchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.action_search));
        SearchManager searchManager = (SearchManager) getSystemService(SEARCH_SERVICE);
        searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
        return true;
    }

    ... 

}

Kết quả

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây


2
Tôi đã nâng cấp nó, nhưng bạn đang sử dụng trình giả lập nào? Tôi đã thử nhưng tôi không nhận được navigate-backnút, mà là biểu tượng tìm kiếm và khoảng cách của nó với cạnh trái của màn hình không giống như giữa Xbiểu tượng và cạnh phải của màn hình (Tôi không có hành động tràn). Đăng câu hỏi ở đây , bạn có thể nhìn vào nó?
Solace

13
nó không phải là một tìm kiếm vật chất. đó chỉ là tìm kiếm cũ thông thường trong thanh hành động
Gopal Singh Sirvi

2
Tôi đã trả lời câu hỏi phụ của riêng tôi, để làm cho nó luôn hiển thị mà không cần phải nhấp vào nút tìm kiếm thêm dòng searchView.setIconifiedByDefault(false);vào onCreateOptionsMenuchức năng.
adelriosantiago

3
một mẩu tin hữu ích khác - nếu bạn muốn mở rộng chế độ tìm kiếm ban đầu, hãy đảm bảo rằng bạn có app:showAsAction="always"và KHÔNGapp:showAsAction="ifRoom|collapseActionView"
Vinay W

1
Ngoài ra, bằng cách sử dụng phương thức này, ngay cả khi searchBar được mở rộng, OverflowIcon vẫn hiển thị (nghĩa là 3 dấu chấm). Nhưng một số ứng dụng, xử lý tìm kiếm, bằng cách mở rộng hoàn toàn và thay đổi nền thành màu trắng. Giống như GMail
Zen

83

Sau một tuần hoang mang về điều này. Tôi nghĩ rằng tôi đã tìm ra nó.
Bây giờ tôi chỉ sử dụng một EditText bên trong Thanh công cụ. Điều này đã được đề xuất với tôi bởi oj88 trên reddit.

Bây giờ tôi có cái này:
Tìm kiếm mới

Đầu tiên bên trong onCreate () của hoạt động của tôi, tôi đã thêm EditText với chế độ xem hình ảnh ở phía bên phải vào Thanh công cụ như thế này:

    // Setup search container view
    searchContainer = new LinearLayout(this);
    Toolbar.LayoutParams containerParams = new Toolbar.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
    containerParams.gravity = Gravity.CENTER_VERTICAL;
    searchContainer.setLayoutParams(containerParams);

    // Setup search view
    toolbarSearchView = new EditText(this);
    // Set width / height / gravity
    int[] textSizeAttr = new int[]{android.R.attr.actionBarSize};
    int indexOfAttrTextSize = 0;
    TypedArray a = obtainStyledAttributes(new TypedValue().data, textSizeAttr);
    int actionBarHeight = a.getDimensionPixelSize(indexOfAttrTextSize, -1);
    a.recycle();
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, actionBarHeight);
    params.gravity = Gravity.CENTER_VERTICAL;
    params.weight = 1;
    toolbarSearchView.setLayoutParams(params);

    // Setup display
    toolbarSearchView.setBackgroundColor(Color.TRANSPARENT);
    toolbarSearchView.setPadding(2, 0, 0, 0);
    toolbarSearchView.setTextColor(Color.WHITE);
    toolbarSearchView.setGravity(Gravity.CENTER_VERTICAL);
    toolbarSearchView.setSingleLine(true);
    toolbarSearchView.setImeActionLabel("Search", EditorInfo.IME_ACTION_UNSPECIFIED);
    toolbarSearchView.setHint("Search");
    toolbarSearchView.setHintTextColor(Color.parseColor("#b3ffffff"));
    try {
        // Set cursor colour to white
        // https://stackoverflow.com/a/26544231/1692770
        // https://github.com/android/platform_frameworks_base/blob/kitkat-release/core/java/android/widget/TextView.java#L562-564
        Field f = TextView.class.getDeclaredField("mCursorDrawableRes");
        f.setAccessible(true);
        f.set(toolbarSearchView, R.drawable.edittext_whitecursor);
    } catch (Exception ignored) {
    }

    // Search text changed listener
    toolbarSearchView.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            Fragment mainFragment = getFragmentManager().findFragmentById(R.id.container);
            if (mainFragment != null && mainFragment instanceof MainListFragment) {
                ((MainListFragment) mainFragment).search(s.toString());
            }
        }

        @Override
        public void afterTextChanged(Editable s) {
            // https://stackoverflow.com/a/6438918/1692770
            if (s.toString().length() <= 0) {
                toolbarSearchView.setHintTextColor(Color.parseColor("#b3ffffff"));
            }
        }
    });
    ((LinearLayout) searchContainer).addView(toolbarSearchView);

    // Setup the clear button
    searchClearButton = new ImageView(this);
    Resources r = getResources();
    int px = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16, r.getDisplayMetrics());
    LinearLayout.LayoutParams clearParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
    clearParams.gravity = Gravity.CENTER;
    searchClearButton.setLayoutParams(clearParams);
    searchClearButton.setImageResource(R.drawable.ic_close_white_24dp); // TODO: Get this image from here: https://github.com/google/material-design-icons
    searchClearButton.setPadding(px, 0, px, 0);
    searchClearButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            toolbarSearchView.setText("");
        }
    });
    ((LinearLayout) searchContainer).addView(searchClearButton);

    // Add search view to toolbar and hide it
    searchContainer.setVisibility(View.GONE);
    toolbar.addView(searchContainer);

Điều này đã làm việc, nhưng sau đó tôi đã gặp một vấn đề trong đó onOptionsItemSelected () không được gọi khi tôi nhấn vào nút home. Vì vậy, tôi không thể hủy tìm kiếm bằng cách nhấn nút home. Tôi đã thử một vài cách khác nhau để đăng ký trình nghe nhấp vào nút home nhưng chúng không hoạt động.

Cuối cùng, tôi phát hiện ra rằng ActionBarDrawerToggle mà tôi đã can thiệp vào mọi thứ, vì vậy tôi đã gỡ bỏ nó. Người nghe này sau đó bắt đầu làm việc:

    toolbar.setNavigationOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // toolbarHomeButtonAnimating is a boolean that is initialized as false. It's used to stop the user pressing the home button while it is animating and breaking things.
            if (!toolbarHomeButtonAnimating) {
                // Here you'll want to check if you have a search query set, if you don't then hide the search box.
                // My main fragment handles this stuff, so I call its methods.
                FragmentManager fragmentManager = getFragmentManager();
                final Fragment fragment = fragmentManager.findFragmentById(R.id.container);
                if (fragment != null && fragment instanceof MainListFragment) {
                    if (((MainListFragment) fragment).hasSearchQuery() || searchContainer.getVisibility() == View.VISIBLE) {
                        displaySearchView(false);
                        return;
                    }
                }
            }

            if (mDrawerLayout.isDrawerOpen(findViewById(R.id.navigation_drawer)))
                mDrawerLayout.closeDrawer(findViewById(R.id.navigation_drawer));
            else
                mDrawerLayout.openDrawer(findViewById(R.id.navigation_drawer));
        }
    });

Vì vậy, bây giờ tôi có thể hủy tìm kiếm bằng nút home, nhưng tôi không thể nhấn nút quay lại để hủy nó. Vì vậy, tôi đã thêm nó vào onBackPression ():

    FragmentManager fragmentManager = getFragmentManager();
    final Fragment mainFragment = fragmentManager.findFragmentById(R.id.container);
    if (mainFragment != null && mainFragment instanceof MainListFragment) {
        if (((MainListFragment) mainFragment).hasSearchQuery() || searchContainer.getVisibility() == View.VISIBLE) {
            displaySearchView(false);
            return;
        }
    }

Tôi đã tạo phương thức này để chuyển đổi mức độ hiển thị của mục EditText và menu:

public void displaySearchView(boolean visible) {
    if (visible) {
        // Stops user from being able to open drawer while searching
        mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);

        // Hide search button, display EditText
        menu.findItem(R.id.action_search).setVisible(false);
        searchContainer.setVisibility(View.VISIBLE);

        // Animate the home icon to the back arrow
        toggleActionBarIcon(ActionDrawableState.ARROW, mDrawerToggle, true);

        // Shift focus to the search EditText
        toolbarSearchView.requestFocus();

        // Pop up the soft keyboard
        new Handler().postDelayed(new Runnable() {
            public void run() {
                toolbarSearchView.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, 0, 0, 0));
                toolbarSearchView.dispatchTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, 0, 0, 0));
            }
        }, 200);
    } else {
        // Allows user to open drawer again
        mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);

        // Hide the EditText and put the search button back on the Toolbar.
        // This sometimes fails when it isn't postDelayed(), don't know why.
        toolbarSearchView.postDelayed(new Runnable() {
            @Override
            public void run() {
                toolbarSearchView.setText("");
                searchContainer.setVisibility(View.GONE);
                menu.findItem(R.id.action_search).setVisible(true);
            }
        }, 200);

        // Turn the home button back into a drawer icon
        toggleActionBarIcon(ActionDrawableState.BURGER, mDrawerToggle, true);

        // Hide the keyboard because the search box has been hidden
        InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(toolbarSearchView.getWindowToken(), 0);
    }
}

Tôi cần một cách để chuyển nút home trên thanh công cụ giữa biểu tượng ngăn kéo và nút quay lại. Cuối cùng tôi đã tìm thấy phương pháp dưới đây trong câu trả lời SO này . Mặc dù tôi đã sửa đổi nó một chút để có ý nghĩa hơn với tôi:

private enum ActionDrawableState {
    BURGER, ARROW
}

/**
 * Modified version of this, https://stackoverflow.com/a/26836272/1692770<br>
 * I flipped the start offset around for the animations because it seemed like it was the wrong way around to me.<br>
 * I also added a listener to the animation so I can find out when the home button has finished rotating.
 */
private void toggleActionBarIcon(final ActionDrawableState state, final ActionBarDrawerToggle toggle, boolean animate) {
    if (animate) {
        float start = state == ActionDrawableState.BURGER ? 1.0f : 0f;
        float end = Math.abs(start - 1);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            ValueAnimator offsetAnimator = ValueAnimator.ofFloat(start, end);
            offsetAnimator.setDuration(300);
            offsetAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
            offsetAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    float offset = (Float) animation.getAnimatedValue();
                    toggle.onDrawerSlide(null, offset);
                }
            });
            offsetAnimator.addListener(new Animator.AnimatorListener() {
                @Override
                public void onAnimationStart(Animator animation) {

                }

                @Override
                public void onAnimationEnd(Animator animation) {
                    toolbarHomeButtonAnimating = false;
                }

                @Override
                public void onAnimationCancel(Animator animation) {

                }

                @Override
                public void onAnimationRepeat(Animator animation) {

                }
            });
            toolbarHomeButtonAnimating = true;
            offsetAnimator.start();
        }
    } else {
        if (state == ActionDrawableState.BURGER) {
            toggle.onDrawerClosed(null);
        } else {
            toggle.onDrawerOpened(null);
        }
    }
}

Điều này hoạt động, tôi đã quản lý để tìm ra một vài lỗi mà tôi tìm thấy trên đường đi. Tôi không nghĩ đó là 100% nhưng nó hoạt động đủ tốt với tôi.

EDIT: Nếu bạn muốn thêm chế độ xem tìm kiếm trong XML thay vì Java, hãy làm điều này:

thanh công cụ:

<android.support.v7.widget.Toolbar 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/toolbar"
    contentInsetLeft="72dp"
    contentInsetStart="72dp"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:background="?attr/colorPrimary"
    android:elevation="4dp"
    android:minHeight="?attr/actionBarSize"
    app:contentInsetLeft="72dp"
    app:contentInsetStart="72dp"
    app:popupTheme="@style/ActionBarPopupThemeOverlay"
    app:theme="@style/ActionBarThemeOverlay">

    <LinearLayout
        android:id="@+id/search_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_vertical"
        android:orientation="horizontal">

        <EditText
            android:id="@+id/search_view"
            android:layout_width="0dp"
            android:layout_height="?attr/actionBarSize"
            android:layout_weight="1"
            android:background="@android:color/transparent"
            android:gravity="center_vertical"
            android:hint="Search"
            android:imeOptions="actionSearch"
            android:inputType="text"
            android:maxLines="1"
            android:paddingLeft="2dp"
            android:singleLine="true"
            android:textColor="#ffffff"
            android:textColorHint="#b3ffffff" />

        <ImageView
            android:id="@+id/search_clear"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:paddingLeft="16dp"
            android:paddingRight="16dp"
            android:src="@drawable/ic_close_white_24dp" />
    </LinearLayout>
</android.support.v7.widget.Toolbar>

onCreate () của Hoạt động của bạn:

    searchContainer = findViewById(R.id.search_container);
    toolbarSearchView = (EditText) findViewById(R.id.search_view);
    searchClearButton = (ImageView) findViewById(R.id.search_clear);

    // Setup search container view
    try {
        // Set cursor colour to white
        // https://stackoverflow.com/a/26544231/1692770
        // https://github.com/android/platform_frameworks_base/blob/kitkat-release/core/java/android/widget/TextView.java#L562-564
        Field f = TextView.class.getDeclaredField("mCursorDrawableRes");
        f.setAccessible(true);
        f.set(toolbarSearchView, R.drawable.edittext_whitecursor);
    } catch (Exception ignored) {
    }

    // Search text changed listener
    toolbarSearchView.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            Fragment mainFragment = getFragmentManager().findFragmentById(R.id.container);
            if (mainFragment != null && mainFragment instanceof MainListFragment) {
                ((MainListFragment) mainFragment).search(s.toString());
            }
        }

        @Override
        public void afterTextChanged(Editable s) {
        }
    });

    // Clear search text when clear button is tapped
    searchClearButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            toolbarSearchView.setText("");
        }
    });

    // Hide the search view
    searchContainer.setVisibility(View.GONE);

Hoạt động tuyệt vời, trông tuyệt vời, cảm ơn bạn! Tuy nhiên, thay vì tạo các bố cục trong mã, tôi đã tạo ra linearLayout với EditText và ImageView trong xml và chỉ thổi phồng nó trong onCreate.
aluxian

Vâng, tôi đã cố gắng thực hiện bằng XML nhưng tôi nghĩ rằng tôi đã làm sai điều gì đó vì Android Studio sẽ không cho tôi tự động hoàn thành trong bố cục XML.
Mike

Bạn có thể vui lòng cập nhật câu trả lời này với thiết kế bố cục XML tương ứng cần thiết cho việc này không? Điều đó có thể giúp đỡ rất tốt.
Shreyash Mahajan

1
@Mike Bạn có thể vui lòng cập nhật câu trả lời của bạn và đặt mã nguồn github hoàn chỉnh của bạn không?
Hamed Ghadirian

1
xin vui lòng gửi dự án hoàn chỉnh trong github
Nilabja


19

Ảnh chụp màn hình đầu tiên trong câu hỏi của bạn không phải là một tiện ích công cộng. Hỗ trợ SearchView ( android.support.v7.widget.SearchView) bắt chước SearchView ( ) của Android 5.0 Lollipop android.widget.SearchView. Ảnh chụp màn hình thứ hai của bạn được sử dụng bởi các ứng dụng được thiết kế bằng vật liệu khác như Google Play.

SearchView trong ảnh chụp màn hình đầu tiên của bạn được sử dụng trong Drive, YouTube và các Ứng dụng Google nguồn đóng khác. May mắn thay, nó cũng được sử dụng trong Trình quay số Android 5.0 . Bạn có thể thử backport view, nhưng nó sử dụng một số API 5.0.

Các lớp mà bạn sẽ muốn xem xét là:

Tìm kiếmEditTextLayout , AnimUtilsDialtactsActivity để hiểu cách sử dụng Chế độ xem. Bạn cũng sẽ cần tài nguyên từ Danh bạ .

May mắn nhất.


Cảm ơn vì đã xem xét điều đó, tôi đã hy vọng có một cái gì đó đã có thể làm được. Hiện tại tôi chỉ sử dụng một EditText với nền trong suốt và có vẻ ổn với những gì tôi cần.
Mike

111
Câu trả lời này rất đáng lo ngại đối với tôi. Tại sao google sử dụng một tiện ích riêng phù hợp với nguyên tắc thiết kế vật liệu của riêng họ và sau đó xuất bản một tiện ích tào lao cho chúng tôi mà không phải vậy? Và mọi nhà phát triển hiện đang phải vật lộn với điều này? Những lý do có thể cho việc này?
Greg Enni

18

Đây là nỗ lực của tôi trong việc này:

Bước 1: Tạo một kiểu có tên SearchViewStyle

<style name="SearchViewStyle" parent="Widget.AppCompat.SearchView">
    <!-- Gets rid of the search icon -->
    <item name="searchIcon">@drawable/search</item>
    <!-- Gets rid of the "underline" in the text -->
    <item name="queryBackground">@null</item>
    <!-- Gets rid of the search icon when the SearchView is expanded -->
    <item name="searchHintIcon">@null</item>
    <!-- The hint text that appears when the user has not typed anything -->
    <item name="queryHint">@string/search_hint</item>
</style>

Bước 2: Tạo bố cục có tên simple_search_view_item.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.SearchView
    android:layout_gravity="end"
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    style="@style/SearchViewStyle"
    xmlns:android="http://schemas.android.com/apk/res/android" />  

Bước 3: Tạo một mục menu cho chế độ tìm kiếm này

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        app:actionLayout="@layout/simple_search_view_item"
        android:title="@string/search"
        android:icon="@drawable/search"
        app:showAsAction="always" />
</menu>  

Bước 4: thổi phồng menu

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.menu_searchable_activity, menu);
    return true;
}  

Kết quả:

nhập mô tả hình ảnh ở đây

Điều duy nhất tôi không thể làm là làm cho nó lấp đầy toàn bộ chiều rộng của Toolbar. Nếu ai đó có thể giúp tôi làm điều đó thì đó sẽ là vàng.


1
I wasn't able to do was to make it fill the entire width, phiên bản thư viện hỗ trợ nào bạn đang sử dụng? Hãy thử cài đặt app:contentInsetStartWithNavigation="0dp"cho Thanh công cụ của bạn.
Mangesh

@LittleChild, hãy thử giải pháp được đưa ra bởi Magnesh. Nếu vẫn không được giải quyết, hãy thử thêm các dòng dưới đây trên thanh công cụ. ứng dụng: contentInsetStartWithNavigation = "0dp" ứng dụng: contentInsetLeft = "0dp" ứng dụng: contentInsetStart = "0dp" ứng dụng: paddingStart = "0dp" android: layout_marginLeft = "0dp" android: layout_marginStart = "0dp"
Shreyash Mahajan

Cảm ơn bạn đã đưa ra lời giải thích cho từng dòng trong SearchViewStyle!
Shinta S

Little Child Đối với toàn bộ chiều rộng, bạn có thể thực hiện sth như thế này: (" stackoverflow.com/questions/27946569/
mẹo

10

Để đạt được giao diện mong muốn của SearchView, bạn có thể sử dụng các kiểu.

Trước tiên, bạn cần tạo stylecho SearchView của mình, trông giống như thế này:

<style name="CustomSearchView" parent="Widget.AppCompat.SearchView">
    <item name="searchIcon">@null</item>
    <item name="queryBackground">@null</item>
</style>

Toàn bộ danh sách các thuộc tính bạn có thể tìm thấy ở đây bài viết, dưới phần "SearchView".

Thứ hai, bạn cần tạo một cái stylecho bạn Toolbar, được sử dụng như ActionBar:

<style name="ToolbarSearchView" parent="Base.ThemeOverlay.AppCompat.Dark.ActionBar">
    <item name="searchViewStyle">@style/CustomSearchView</item>
</style>

Và cuối cùng, bạn cần cập nhật thuộc tính chủ đề Thanh công cụ theo cách này:

<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    app:theme="@style/ToolbarSearchView" />

Kết quả:

nhập mô tả hình ảnh ở đây

LƯU Ý: Bạn cần thay đổi Toolbarthuộc tính chủ đề của bạn trực tiếp. Nếu bạn chỉ cập nhật searchViewStylethuộc tính chủ đề chính của mình, nó sẽ không ảnh hưởng đến bạn Toolbar.


Này, bạn đã tự thêm các biểu tượng đó navigate-back(mũi tên lùi) và cancel(x) hay chúng được tự động thêm vào?
Solace

1
@Solace chúng được thêm tự động
Artem

Chúng chỉ xuất hiện khi bạn bắt đầu viết truy vấn tìm kiếm trong SearchView hoặc chúng có ở đó ngay cả khi bạn chưa viết gì và gợi ý tìm kiếm có thể nhìn thấy không? Tôi đang hỏi bởi vì tôi không xuất hiện cho đến khi tôi bắt đầu viết truy vấn. Vì vậy, thông tin này sẽ rất hữu ích cho tôi
Solace

1
@Solace navigate-backluôn được hiển thị, clearchỉ được hiển thị sau khi bạn viết một số truy vấn tìm kiếm.
Nữ hoàng

6

Một cách khác để bạn có thể đạt được hiệu quả mong muốn là sử dụng thư viện Chế độ xem tìm kiếm vật liệu này . Nó tự động xử lý lịch sử tìm kiếm và cũng có thể cung cấp các đề xuất tìm kiếm cho chế độ xem.

Ví dụ: (Nó được hiển thị bằng tiếng Bồ Đào Nha, nhưng nó cũng hoạt động bằng tiếng Anh và tiếng Ý).

Mẫu vật

Thiết lập

Trước khi bạn có thể sử dụng lib này, bạn phải triển khai một lớp có tên MsvAuthoritybên trong br.com.maukergói trên mô-đun ứng dụng của bạn và nó phải có một biến Chuỗi tĩnh công khai được gọi CONTENT_AUTHORITY. Cung cấp cho nó giá trị bạn muốn và đừng quên thêm cùng tên vào tệp kê khai của bạn. Lib sẽ sử dụng tệp này để đặt quyền cho Nhà cung cấp nội dung.

Thí dụ:

MsvAuthority.java

package br.com.mauker;

public class MsvAuthority {
    public static final String CONTENT_AUTHORITY = "br.com.mauker.materialsearchview.searchhistorydatabase";
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest ...>

    <application ... >
        <provider
        android:name="br.com.mauker.materialsearchview.db.HistoryProvider"
        android:authorities="br.com.mauker.materialsearchview.searchhistorydatabase"
        android:exported="false"
        android:protectionLevel="signature"
        android:syncable="true"/>
    </application>

</manifest>

Sử dụng

Để sử dụng nó, thêm phụ thuộc:

compile 'br.com.mauker.materialsearchview:materialsearchview:1.2.0'

Và sau đó, trên Activitytệp bố trí của bạn , thêm vào như sau:

<br.com.mauker.materialsearchview.MaterialSearchView
    android:id="@+id/search_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

Sau đó, bạn sẽ chỉ cần có được MaterialSearchViewtài liệu tham khảo bằng cách sử dụng getViewById()và mở nó lên hoặc đóng nó bằng cách sử dụng MaterialSearchView#openSearch()MaterialSearchView#closeSearch().

PS: Có thể mở và đóng chế độ xem không chỉ từ Toolbar. openSearch()Về cơ bản Button, bạn có thể sử dụng phương thức bất kỳ , chẳng hạn như Nút hành động nổi.

// Inside onCreate()
MaterialSearchView searchView = (MaterialSearchView) findViewById(R.id.search_view);
Button bt = (Button) findViewById(R.id.button);

bt.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            searchView.openSearch();
        }
    });

Bạn cũng có thể đóng chế độ xem bằng nút quay lại, thực hiện như sau:

@Override
public void onBackPressed() {
    if (searchView.isOpen()) {
        // Close the search on the back button press.
        searchView.closeSearch();
    } else {
        super.onBackPressed();
    }
}

Để biết thêm thông tin về cách sử dụng lib, hãy kiểm tra trang github .


2
Thư viện tuyệt vời và ý tưởng tuyệt vời để trừu tượng hóa phương thức mở / đóng để MenuItem không bắt buộc phải mở / đóng nó, tôi dự định sử dụng nó trong ứng dụng của mình với FloatingActionButton với biểu tượng tìm kiếm, vì vậy nó sẽ hoạt động rất tốt.
AdamMc331

Tại sao không có tham số cho các chuỗi như 'Tìm kiếm'? Dường như thư viện giới hạn mọi người trong các phiên bản tiếng Anh hoặc tiếng Bồ Đào Nha của chuỗi: /
Aspires Dev

Nhưng có thể thay đổi Chuỗi gợi ý bằng cách sử dụng các kiểu như đã nêu trên README. Đối với gợi ý nhập giọng nói, nó sẽ được phát hành sau: github.com/Mauker1/M vật liệu
kiếm / 23:00

@rpgmaker Kiểm tra bản cập nhật mới nhất, giờ đây có thể thay đổi các chuỗi đó.
Mauker

@Mauker có ý tưởng nào để đặt android: imeOptions = "actionSearch" thành EditText của thành phần của bạn không? (Tôi muốn hiển thị nút "tìm kiếm" trong bàn phím)
Greg

2

Phần sau đây sẽ tạo SearchView giống hệt với SearchView trong Gmail và thêm nó vào Thanh công cụ đã cho. Bạn sẽ chỉ phải thực hiện phương thức "ViewUtil.convertDpToPixel" của riêng bạn.

private SearchView createMaterialSearchView(Toolbar toolbar, String hintText) {

    setSupportActionBar(toolbar);
    ActionBar actionBar = getSupportActionBar();
    actionBar.setDisplayHomeAsUpEnabled(true);
    actionBar.setDisplayShowCustomEnabled(true);
    actionBar.setDisplayShowTitleEnabled(false);

    SearchView searchView = new SearchView(this);
    searchView.setIconifiedByDefault(false);
    searchView.setMaxWidth(Integer.MAX_VALUE);
    searchView.setMinimumHeight(Integer.MAX_VALUE);
    searchView.setQueryHint(hintText);

    int rightMarginFrame = 0;
    View frame = searchView.findViewById(getResources().getIdentifier("android:id/search_edit_frame", null, null));
    if (frame != null) {
        LinearLayout.LayoutParams frameParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        rightMarginFrame = ((LinearLayout.LayoutParams) frame.getLayoutParams()).rightMargin;
        frameParams.setMargins(0, 0, 0, 0);
        frame.setLayoutParams(frameParams);
    }

    View plate = searchView.findViewById(getResources().getIdentifier("android:id/search_plate", null, null));
    if (plate != null) {
        plate.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        plate.setPadding(0, 0, rightMarginFrame, 0);
        plate.setBackgroundColor(Color.TRANSPARENT);
    }

    int autoCompleteId = getResources().getIdentifier("android:id/search_src_text", null, null);
    if (searchView.findViewById(autoCompleteId) != null) {
        EditText autoComplete = (EditText) searchView.findViewById(autoCompleteId);
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, (int) ViewUtil.convertDpToPixel(36));
        params.weight = 1;
        params.gravity = Gravity.CENTER_VERTICAL;
        params.leftMargin = rightMarginFrame;
        autoComplete.setLayoutParams(params);
        autoComplete.setTextSize(16f);
    }

    int searchMagId = getResources().getIdentifier("android:id/search_mag_icon", null, null);
    if (searchView.findViewById(searchMagId) != null) {
        ImageView v = (ImageView) searchView.findViewById(searchMagId);
        v.setImageDrawable(null);
        v.setPadding(0, 0, 0, 0);
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
        params.setMargins(0, 0, 0, 0);
        v.setLayoutParams(params);
    }

    toolbar.setTitle(null);
    toolbar.setContentInsetsAbsolute(0, 0);
    toolbar.addView(searchView);

    return searchView;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.