์นดํ…Œ๊ณ ๋ฆฌ ๋ณด๊ด€๋ฌผ: Android

Android

๋จธํ‹ฐ๋ฆฌ์–ผ ๋””์ž์ธ ๊ฐ€์ด๋“œ ๋ผ์ธ์ฒ˜๋Ÿผ ๋ณด์ด๋Š” SearchView ์ƒ์„ฑ ์—†์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋‚ด ๋ฉ”๋‰ด XML์ž…๋‹ˆ๋‹ค. <?xml version=โ€1.0โ€ณ encoding=โ€utf-8โ€ณ?> <menu

ํ˜„์žฌ ์•ฑ์„ ๋จธํ‹ฐ๋ฆฌ์–ผ ๋””์ž์ธ์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ฐฐ์šฐ๋Š” ์ค‘์ž…๋‹ˆ๋‹ค. ์ง€๊ธˆ ์กฐ๊ธˆ ๋ฉˆ์ท„์Šต๋‹ˆ๋‹ค. ํˆด๋ฐ”๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ๊ณ  ๋‚ด ํƒ์ƒ‰ ์„œ๋ž์ด ๋ชจ๋“  ์ฝ˜ํ…์ธ ๋ฅผ ์˜ค๋ฒ„๋ ˆ์ดํ•˜๋„๋ก ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

์ด์ œ ์žฌ๋ฃŒ ๊ฐ€์ด๋“œ ๋ผ์ธ ๊ณผ ๋น„์Šทํ•œ ํ™•์žฅ ๊ฐ€๋Šฅํ•œ ๊ฒ€์ƒ‰์„ ์ž‘์„ฑํ•˜๋ ค๊ณ ํ•ฉ๋‹ˆ๋‹ค .
์—ฌ๊ธฐ์— ์ด๋ฏธ์ง€ ์„ค๋ช…์„ ์ž…๋ ฅํ•˜์‹ญ์‹œ์˜ค

์ด๊ฒƒ์ด ๋ฐ”๋กœ ์ง€๊ธˆ ์–ป์€ ๊ฒƒ์ด๋ฉฐ ์œ„์™€ ๊ฐ™์ด ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๋‚ด ๋ฉ”๋‰ด 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>

์ž‘๋™ํ•˜์ง€๋งŒ SearchView๋กœ ํ™•์žฅ๋˜๋Š” ๋ฉ”๋‰ด ํ•ญ๋ชฉ์ด ํ‘œ์‹œ๋˜๋ฉฐ ๋‚ด ๋ชฉ๋ก์„ ์ž˜ ํ•„ํ„ฐ๋ง ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜๋„ ์ฒซ ๋ฒˆ์งธ ๊ทธ๋ฆผ์ฒ˜๋Ÿผ ๋ณด์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ์‚ฌ์šฉํ•˜๋ ค๊ณ  MenuItemCompat.setOnActionExpandListener()์— R.id.action_search๋‚˜๋Š” ๋’ค๋กœ ํ™”์‚ดํ‘œ์— ํ™ˆ ์•„์ด์ฝ˜์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋„๋ก,ํ•˜์ง€๋งŒ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ฆฌ์Šค๋„ˆ์—์„œ ์•„๋ฌด๊ฒƒ๋„ ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์ด ํšจ๊ณผ๊ฐ€ ์žˆ์—ˆ์ง€๋งŒ ์—ฌ์ „ํžˆ ์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€์— ๊ทธ๋ฆฌ ๊ฐ€๊น์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.

์žฌ๋ฃŒ ๊ฐ€์ด๋“œ ๋ผ์ธ์ฒ˜๋Ÿผ ๋ณด์ด๋Š” ์ƒˆ๋กœ์šด appcompat ๋„๊ตฌ ๋ชจ์Œ์—์„œ SearchView๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•



๋‹ต๋ณ€

android.support.v7๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์‹ค์ œ๋กœ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด ๋งค์šฐ ์‰ฝ์Šต๋‹ˆ๋‹ค .

1 ๋‹จ๊ณ„

๋ฉ”๋‰ด ํ•ญ๋ชฉ ์„ ์–ธ

<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" />

2 ๋‹จ๊ณ„

SearchView๋ฅผ ํ™•์žฅ AppCompatActivityํ•˜๊ณ  onCreateOptionsMenu์„ค์ •ํ•˜์‹ญ์‹œ์˜ค.

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

    ... 

}

๊ฒฐ๊ณผ


๋‹ต๋ณ€

์ผ์ฃผ์ผ ๋™์•ˆ ์ˆ˜์ˆ˜๊ป˜๋ผ๋ฅผ ํ‘ผ ํ›„. ๋‚ด๊ฐ€ ์•Œ์•„ ๋‚ธ ๊ฒƒ ๊ฐ™์•„
ํˆด๋ฐ” ๋‚ด์—์„œ EditText ๋งŒ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ reddit์—์„œ oj88์— ์˜ํ•ด ์ œ์•ˆ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ด์ œ ์ด๊ฒƒ์„ ๊ฐ€์ง€๊ณ ์žˆ๋‹ค :

๋จผ์ € ๋‚ด ํ™œ๋™์˜ onCreate () ๋‚ด๋ถ€์— ์˜ค๋ฅธ์ชฝ๊ณผ ๊ฐ™์ด ์ด๋ฏธ์ง€๋ณด๊ธฐ๊ฐ€์žˆ๋Š” EditText๋ฅผ ํˆด๋ฐ”์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ถ”๊ฐ€ํ–ˆ๋‹ค :

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

์ด๊ฒƒ์€ ํšจ๊ณผ๊ฐ€ ์žˆ์—ˆ์ง€๋งŒ ํ™ˆ ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ onOptionsItemSelected ()๊ฐ€ ํ˜ธ์ถœ๋˜์ง€ ์•Š๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ํ™ˆ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ๊ฒ€์ƒ‰์„ ์ทจ์†Œ ํ•  ์ˆ˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค. ํ™ˆ ๋ฒ„ํŠผ์— ํด๋ฆญ ๋ฆฌ์Šค๋„ˆ๋ฅผ ๋“ฑ๋กํ•˜๋Š” ๋ช‡ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ์‹œ๋„ํ–ˆ์ง€๋งŒ ์ž‘๋™ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

๊ฒฐ๊ตญ ๋‚˜๋Š” ๊ฐ€์ง€๊ณ  ์žˆ๋˜ ActionBarDrawerToggle์ด ๋ฌผ๊ฑด์„ ๋ฐฉํ•ดํ•˜๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•˜์œผ๋ฏ€๋กœ ๊ทธ๊ฒƒ์„ ์ œ๊ฑฐํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฆฌ์Šค๋„ˆ๋Š” ๋‹ค์Œ ์ž‘์—…์„ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค.

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

์ด์ œ ํ™ˆ ๋ฒ„ํŠผ์œผ๋กœ ๊ฒ€์ƒ‰์„ ์ทจ์†Œ ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๋’ค๋กœ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ์ทจ์†Œ ํ•  ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ด๊ฒƒ์„ onBackPressed ()์— ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

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

์ด ๋ฉ”์†Œ๋“œ๋ฅผ ์ž‘์„ฑํ•˜์—ฌ EditText ๋ฐ ๋ฉ”๋‰ด ํ•ญ๋ชฉ์˜ ๊ฐ€์‹œ์„ฑ์„ ํ† ๊ธ€ํ•ฉ๋‹ˆ๋‹ค.

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

ํˆด๋ฐ”์˜ ํ™ˆ ๋ฒ„ํŠผ์„ ์„œ๋ž ์•„์ด์ฝ˜๊ณผ ๋’ค๋กœ ๋ฒ„ํŠผ ์‚ฌ์ด์—์„œ ์ „ํ™˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ํ•„์š”ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ฒฐ๊ตญ ์ด SO ๋‹ต๋ณ€ ์—์„œ ์•„๋ž˜ ๋ฐฉ๋ฒ•์„ ์ฐพ์•˜์Šต๋‹ˆ๋‹ค . ์ข€ ๋” ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๊ฒŒ ์•ฝ๊ฐ„ ์ˆ˜์ •ํ–ˆ์ง€๋งŒ :

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

์ด๊ฒƒ์€ ํšจ๊ณผ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ธธ์„ ๋”ฐ๋ผ ์ฐพ์€ ๋ช‡ ๊ฐ€์ง€ ๋ฒ„๊ทธ๋ฅผ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด 100 %๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์ง€๋งŒ ๊ทธ๊ฒƒ์€ ๋‚˜๋ฅผ ์œ„ํ•ด ์ถฉ๋ถ„ํžˆ ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

ํŽธ์ง‘ : Java ๋Œ€์‹  XML๋กœ ๊ฒ€์ƒ‰๋ณด๊ธฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•˜์‹ญ์‹œ์˜ค.

toolbar.xml :

<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 () :

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

๋‹ต๋ณ€

๋‚˜๋Š” ์˜ค๋ž˜๋œ ์Šค๋ ˆ๋“œ๋ฅผ ์•Œ๊ณ  ์žˆ์ง€๋งŒ ์—ฌ์ „ํžˆ ๋ฐฉ๊ธˆ ๋งŒ๋“  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๊ฒŒ์‹œํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋ˆ„๊ตฐ๊ฐ€๋ฅผ ๋„์šธ ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

https://github.com/Shahroz16/material-searchview


๋‹ต๋ณ€

์งˆ๋ฌธ์˜ ์ฒซ ๋ฒˆ์งธ ์Šคํฌ๋ฆฐ ์ƒท์€ ๊ณต๊ฐœ ์œ„์ ฏ์ด ์•„๋‹™๋‹ˆ๋‹ค. ์ง€์› SearchView ( android.support.v7.widget.SearchView)๋Š” Android 5.0 Lollipop์˜ SearchView ( android.widget.SearchView)์™€ ์œ ์‚ฌ ํ•ฉ๋‹ˆ๋‹ค. ๋‘ ๋ฒˆ์งธ ์Šคํฌ๋ฆฐ ์ƒท์€ Google Play์™€ ๊ฐ™์€ ๋‹ค๋ฅธ ์žฌ๋ฃŒ๋กœ ์„ค๊ณ„๋œ ์•ฑ์—์„œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

์ฒซ ๋ฒˆ์งธ ์Šคํฌ๋ฆฐ ์ƒท์˜ SearchView๋Š” ๋“œ๋ผ์ด๋ธŒ, YouTube ๋ฐ ๊ธฐํƒ€ ๋น„๊ณต๊ฐœ ์†Œ์Šค Google Apps์—์„œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ๋‹คํ–‰ํžˆ๋„ Android 5.0 Dialer ์—์„œ๋„ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค . ๋ทฐ๋ฅผ ๋ฐฑ ํฌํŠธํ•˜๋ ค๊ณ  ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์ผ๋ถ€ 5.0 API๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋ณด๊ณ  ์‹ถ์€ ์ˆ˜์—…์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

SearchEditTextLayout , AnimUtils ๋ฐ DialtactsActivity ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ View ์‚ฌ์šฉ ๋ฐฉ๋ฒ•์„ ์ดํ•ดํ•˜์‹ญ์‹œ์˜ค. ContactsCommon์˜ ๋ฆฌ์†Œ์Šค๋„ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค .

ํ–‰์šด์„ ๋น•๋‹ˆ๋‹ค.


๋‹ต๋ณ€

์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋ ค๋Š” ์‹œ๋„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

1 ๋‹จ๊ณ„ : ์ด๋ฆ„์ด ์ง€์ •๋œ ์Šคํƒ€์ผ ๋งŒ๋“ค๊ธฐ 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>

2 ๋‹จ๊ณ„ : ์ด๋ฆ„์ด ์ง€์ •๋œ ๋ ˆ์ด์•„์›ƒ ์ƒ์„ฑ 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" />  

3 ๋‹จ๊ณ„ :์ด ๊ฒ€์ƒ‰๋ณด๊ธฐ์— ๋Œ€ํ•œ ๋ฉ”๋‰ด ํ•ญ๋ชฉ ์ž‘์„ฑ

<?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>  

4 ๋‹จ๊ณ„ : ๋ฉ”๋‰ด ํŒฝ์ฐฝ

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

๊ฒฐ๊ณผ:

๋‚ด๊ฐ€ ํ•  ์ˆ˜ ์—†์—ˆ๋˜ ์œ ์ผํ•œ ๊ฒƒ์€์˜ ์ „์ฒด ๋„ˆ๋น„๋ฅผ ์ฑ„์šฐ๋Š” ๊ฒƒ Toolbar์ž…๋‹ˆ๋‹ค. ๋ˆ„๊ตฐ๊ฐ€ ๋‚ด๊ฐ€ ๊ทธ๋ ‡๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ๊ทธ๊ฒƒ์€ ํ™ฉ๊ธˆ์ƒ‰ ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.


๋‹ต๋ณ€

์›ํ•˜๋Š” SearchView ๋ชจ์–‘์„ ์–ป๊ธฐ ์œ„ํ•ด ์Šคํƒ€์ผ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋จผ์ € styleSearchView ๋ฅผ ์ž‘์„ฑ ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

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

์ด ๊ธฐ์‚ฌ์˜ โ€œSearchViewโ€์„น์…˜ ์—์„œ ์ฐพ์„ ์ˆ˜์žˆ๋Š” ์ „์ฒด ์†์„ฑ ๋ชฉ๋ก์ž…๋‹ˆ๋‹ค .

๋‘˜์งธ, ๋‹น์‹ ์€์„ ๋งŒ๋“ค ํ•„์š”๊ฐ€ style๋‹น์‹ ์„ ์œ„ํ•ด Toolbar, ์•ก์…˜ ๋ฐ”๋กœ ์‚ฌ์šฉ๋œ๋‹ค :

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

๋งˆ์ง€๋ง‰์œผ๋กœ ํˆด๋ฐ” ํ…Œ๋งˆ ์†์„ฑ์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์—…๋ฐ์ดํŠธํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

<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" />

๊ฒฐ๊ณผ:

์ฐธ๊ณ  : Toolbarํ…Œ๋งˆ ์†์„ฑ์„ ์ง์ ‘ ๋ณ€๊ฒฝํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค . ๊ธฐ๋ณธ ํ…Œ๋งˆ searchViewStyle์†์„ฑ ๋งŒ ์—…๋ฐ์ดํŠธํ•˜๋ฉด์— ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค Toolbar.


๋‹ต๋ณ€

์›ํ•˜๋Š” ํšจ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜์žˆ๋Š” ๋˜ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์€์ด ์žฌ๋ฃŒ ๊ฒ€์ƒ‰ ๋ทฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ ์ž…๋‹ˆ๋‹ค. ๊ฒ€์ƒ‰ ๊ธฐ๋ก์„ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋ฉฐ๋ณด๊ธฐ์— ๊ฒ€์ƒ‰ ์ œ์•ˆ์„ ์ œ๊ณต ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์ƒ˜ํ”Œ : (ํฌ๋ฅดํˆฌ๊ฐˆ์–ด๋กœ ํ‘œ์‹œ๋˜์ง€๋งŒ ์˜์–ด์™€ ์ดํƒˆ๋ฆฌ์•„์–ด๋กœ๋„ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค).

์„ค์ •

์ด lib๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์ „์— ์•ฑ ๋ชจ๋“ˆ MsvAuthority์˜ br.com.maukerํŒจํ‚ค์ง€ ๋‚ด์— ์ด๋ฆ„์ด ์ง€์ •๋œ ํด๋ž˜์Šค๋ฅผ ๊ตฌํ˜„ ํ•ด์•ผํ•˜๋ฉฐ๋ผ๋Š” ๊ณต์šฉ ์ •์  ๋ฌธ์ž์—ด ๋ณ€์ˆ˜๊ฐ€ ์žˆ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค CONTENT_AUTHORITY. ์›ํ•˜๋Š” ๊ฐ’์„ ์ง€์ •ํ•˜๊ณ  ๋งค๋‹ˆํŽ˜์ŠคํŠธ ํŒŒ์ผ์— ๋™์ผํ•œ ์ด๋ฆ„์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์„ ์žŠ์ง€ ๋งˆ์‹ญ์‹œ์˜ค . lib๋Š”์ด ํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ปจํ…์ธ  ์ œ๊ณต์ž ๊ถŒํ•œ์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ:

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>

์šฉ๋ฒ•

์‚ฌ์šฉํ•˜๋ ค๋ฉด ์ข…์†์„ฑ์„ ์ถ”๊ฐ€ํ•˜์‹ญ์‹œ์˜ค.

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

๊ทธ๋Ÿฐ ๋‹ค์Œ Activity๋ ˆ์ด์•„์›ƒ ํŒŒ์ผ์—์„œ ๋‹ค์Œ์„ ์ถ”๊ฐ€ํ•˜์‹ญ์‹œ์˜ค.

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

๊ทธ ํ›„, ๋‹น์‹ ์€ ๋‹จ์ง€ ์–ป์„ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค MaterialSearchView์‚ฌ์šฉํ•˜์—ฌ ์ฐธ์กฐ๋ฅผ getViewById()ํ•˜๊ณ , ๊ทธ๊ฒƒ์„ ์—ด๊ฑฐ ๋‚˜ ์‚ฌ์šฉํ•˜์—ฌ ์ข…๋ฃŒ MaterialSearchView#openSearch()ํ•˜๊ณ  MaterialSearchView#closeSearch().

์ถ”์‹  : ์—์„œ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ๋ณด๊ธฐ๋ฅผ ์—ด๊ณ  ๋‹ซ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค Toolbar. ํ”Œ๋กœํŒ… ์•ก์…˜ ๋ฒ„ํŠผ๊ณผ ๊ฐ™์€ openSearch()๊ธฐ๋ณธ์ ์œผ๋กœ ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค Button.

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

๋’ค๋กœ ๋ฒ„ํŠผ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•˜์—ฌ๋ณด๊ธฐ๋ฅผ ๋‹ซ์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

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

lib ์‚ฌ์šฉ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ ์€ github ํŽ˜์ด์ง€๋ฅผ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค .


์ด ๊ธ€์€ Android ์นดํ…Œ๊ณ ๋ฆฌ๋กœ ๋ถ„๋ฅ˜๋˜์—ˆ๊ณ  ๋‹˜์— ์˜ํ•ด ์— ์ž‘์„ฑ๋์Šต๋‹ˆ๋‹ค.