如何检测SearchView的后退按钮?

时间:2016-05-04 23:00:50

标签: android android-layout searchview android-search

我使用单个活动来显示SearchView以及显示搜索结果。搜索结果只是项目的子集,因此搜索充当过滤器。一切似乎都运行正常,但是当我点击SearchView的后退按钮时,我无法弄清楚如何恢复视图中的所有项目。

或许还有另一种方法可以检测用户何时从搜索结果导航到上一个视图(在我的情况下,是同一个视图)。

由于

4 个答案:

答案 0 :(得分:32)

因此,查看问题的标题,您不确定如何检测private void setFontColor(Color fontColor) { JFreeChart chart = getChart(); chart.getTitle().setPaint(fontColor); Plot plot = chart.getPlot(); if (plot instanceof CategoryPlot) { setAxisFontColor(((CategoryPlot) plot).getDomainAxis(), fontColor); setAxisFontColor(((CategoryPlot) plot).getRangeAxis(), fontColor); } else if (plot instanceof XYPlot) { setAxisFontColor(((XYPlot) plot).getDomainAxis(), fontColor); setAxisFontColor(((XYPlot) plot).getRangeAxis(), fontColor); } } private void setAxisFontColor(Axis axis, Color fontColor) { if (!fontColor.equals(axis.getLabelPaint())) axis.setLabelPaint(fontColor); if (!fontColor.equals(axis.getTickLabelPaint())) axis.setTickLabelPaint(fontColor); } 何时被关闭,因此当{时,您无法将视图恢复为“正常”状态{1}}不再打开。

从Android 4.0 +开始的过时解决方案

(简单)解决方案是向您的SearchView添加:SearchView,如下所示:

SearchView.OnCloseListener

修改

更新的解决方案适用于Android 4.0 +

显然SearchView有问题,并且不适用于较新版本的Android(4.0+)。请参阅:https://code.google.com/p/android/issues/detail?id=25758

解决方法是使用SearchView.setOnCloseListener(new SearchView.OnCloseListener() { @Override public boolean onClose() { // This is where you can be notified when the `SearchView` is closed // and change your views you see fit. } }); 的支持库版本:

我的OnCloseListener看起来像这样:

SearchView

至于为什么谷歌甚至不愿意在我不知道的文档中写评论,但这很难过。

<强> EDIT2

只需在评论中添加@MateiRadu添加的链接:

how to handle back button of Search View in android

这也显示了如何使用onCreateOptionsMenu代替@Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu, menu); MenuItem searchMenuItem = menu.findItem(R.id.searchView); SearchView searchView = (SearchView) searchMenuItem.getActionView(); MenuItemCompat.setOnActionExpandListener(searchMenuItem, new MenuItemCompat.OnActionExpandListener() { @Override public boolean onMenuItemActionExpand(MenuItem item) { Toast.makeText(ScrollingActivity.this, "onMenuItemActionExpand called", Toast.LENGTH_SHORT).show(); return true; } @Override public boolean onMenuItemActionCollapse(MenuItem item) { Toast.makeText(ScrollingActivity.this, "onMenutItemActionCollapse called", Toast.LENGTH_SHORT).show(); return true; } }); }

希望这有帮助。

答案 1 :(得分:4)

Darwind的答案将完成这项工作,但只有当用户按下后退按钮关闭键盘并且SearchView不再有焦点时才会有效。

更好的方法是听取SearchView的文字更改 这样,您可以在文本更新时恢复视图和控制UI 我是怎么做的。

SearchView searchView = new SearchView(context);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
    @Override
    public boolean onQueryTextSubmit(String query) {
        // this is when user is done typing and clicks search
        return false;
    }

    @Override
    public boolean onQueryTextChange(String newText) {
        // you can use this to do a "live" search while the user is typing.
        // this will trigger each time user changes (adds or removes) text
        // so when newText is empty, restore your views
        return false;
    }
});

答案 2 :(得分:3)

此处所有代码均已已弃用!您应该使用类似这样的东西。

import logging

from django.conf import settings
from django.contrib import messages
from django.contrib.auth import login
from django.http import HttpResponse
from django.utils.translation import ugettext as _
from django.views.generic import FormView
from django.views.generic import TemplateView
from django.views.generic import View

from mama_cas.compat import defused_etree
from mama_cas.compat import is_authenticated
from mama_cas.exceptions import ValidationError
from mama_cas.forms import LoginForm
from mama_cas.mixins import CasResponseMixin
from mama_cas.mixins import CsrfProtectMixin
from mama_cas.mixins import LoginRequiredMixin
from mama_cas.cas import logout_user
from mama_cas.cas import validate_service_ticket
from mama_cas.cas import validate_proxy_ticket
from mama_cas.cas import validate_proxy_granting_ticket
from mama_cas.mixins import NeverCacheMixin
from mama_cas.models import ProxyTicket
from mama_cas.models import ServiceTicket
from mama_cas.response import ValidationResponse
from mama_cas.response import ProxyResponse
from mama_cas.response import SamlValidationResponse
from mama_cas.services import service_allowed
from mama_cas.utils import add_query_params
from mama_cas.utils import clean_service_url
from mama_cas.utils import redirect
from mama_cas.utils import to_bool


logger = logging.getLogger(__name__)


login_view_template_name = getattr(settings,
                                   'MAMA_CAS_LOGIN_TEMPLATE',
                                   'mama_cas/login.html')

warn_view_template_name = getattr(settings,
                                  'MAMA_CAS_WARN_TEMPLATE',
                                  'mama_cas/warn.html')


class LoginView(CsrfProtectMixin, NeverCacheMixin, FormView):
    """
    (2.1 and 2.2) Credential requestor and acceptor.

    This view operates as a credential requestor when a GET request
    is received, and a credential acceptor for POST requests.
    """
    template_name = login_view_template_name
    form_class = LoginForm

    def get_form_kwargs(self):
        """
        Django >= 1.11 supports a request sent to the authenticator
        so we grab that here and pass it along to the form so it can be
        handed off to the authenticators.
        """
        kwargs = super(LoginView, self).get_form_kwargs()
        kwargs['request'] = self.request
        return kwargs

    def get(self, request, *args, **kwargs):
        """
        (2.1) As a credential requestor, /login accepts three optional
        parameters:

        1. ``service``: the identifier of the application the client is
           accessing. We assume this identifier to be a URL.
        2. ``renew``: requires a client to present credentials
           regardless of any existing single sign-on session.
        3. ``gateway``: causes the client to not be prompted for
           credentials. If a single sign-on session exists the user
           will be logged in and forwarded to the specified service.
           Otherwise, the user remains logged out and is forwarded to
           the specified service.
        """
        service = request.GET.get('service')
        renew = to_bool(request.GET.get('renew'))
        gateway = to_bool(request.GET.get('gateway'))

        if renew:
            logger.debug("Renew request received by credential requestor")
        elif gateway and service:
            logger.debug("Gateway request received by credential requestor")
            if is_authenticated(request.user):
                st = ServiceTicket.objects.create_ticket(service=service, user=request.user)
                if self.warn_user():
                    return redirect('cas_warn', params={'service': service, 'ticket': st.ticket})
                return redirect(service, params={'ticket': st.ticket})
            else:
                return redirect(service)
        elif is_authenticated(request.user):
            if service:
                logger.debug("Service ticket request received by credential requestor")
                st = ServiceTicket.objects.create_ticket(service=service, user=request.user)
                if self.warn_user():
                    return redirect('cas_warn', params={'service': service, 'ticket': st.ticket})
                return redirect(service, params={'ticket': st.ticket})
            else:
                msg = _("You are logged in as %s") % request.user
                messages.success(request, msg)
        return super(LoginView, self).get(request, *args, **kwargs)

    def warn_user(self):
        """
        Returns ``True`` if the ``warn`` parameter is set in the
        current session. Otherwise, returns ``False``.
        """
        return self.request.session.get('warn', False)

    def form_valid(self, form):
        """
        (2.2) As a credential acceptor, /login requires two parameters:

        1. ``username``: the username provided by the client
        2. ``password``: the password provided by the client

        If authentication is successful, the single sign-on session is
        created. If a service is provided, a ``ServiceTicket`` is
        created and the client is redirected to the service URL with
        the ``ServiceTicket`` included. If no service is provided, the
        login page is redisplayed with a message indicating a
        successful login.

        If authentication fails, the login form is redisplayed with an
        error message describing the reason for failure.

        The credential acceptor accepts one optional parameter:

        1. ``warn``: causes the user to be prompted when successive
           authentication attempts occur within the single sign-on
           session.
        """
        login(self.request, form.user)
        logger.info("Single sign-on session started for %s" % form.user)

        if form.cleaned_data.get('warn'):
            self.request.session['warn'] = True

        service = self.request.GET.get('service')
        if service:
            st = ServiceTicket.objects.create_ticket(service=service, user=self.request.user, primary=True)
            return redirect(service, params={'ticket': st.ticket})
        return redirect('cas_login')


class WarnView(NeverCacheMixin, LoginRequiredMixin, TemplateView):
    """
    (2.2.1) Disables transparent authentication by informing the user
    that service authentication is taking place. The user can choose
    to continue or cancel the authentication attempt.
    """
    template_name = warn_view_template_name

    def get(self, request, *args, **kwargs):
        service = request.GET.get('service')
        ticket = request.GET.get('ticket')

        if not service_allowed(service):
            return redirect('cas_login')

        msg = _("Do you want to access %(service)s as %(user)s?") % {
                'service': clean_service_url(service),
                'user': request.user}
        messages.info(request, msg)
        kwargs['service'] = add_query_params(service, {'ticket': ticket})
        return super(WarnView, self).get(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        return kwargs


class LogoutView(NeverCacheMixin, View):
    """
    (2.3) End a client's single sign-on session.

    Accessing this view ends an existing single sign-on session,
    requiring a new single sign-on session to be established for
    future authentication attempts.

    (2.3.1) If ``service`` is specified and
    ``MAMA_CAS_FOLLOW_LOGOUT_URL`` is ``True``, the client will be
    redirected to the specified service URL. [CAS 3.0]
    """
    def get(self, request, *args, **kwargs):
        service = request.GET.get('service')
        if not service:
            service = request.GET.get('url')
        follow_url = getattr(settings, 'MAMA_CAS_FOLLOW_LOGOUT_URL', True)
        logout_user(request)
        if service and follow_url:
            return redirect(service)
        return redirect('cas_login')


class ValidateView(NeverCacheMixin, View):
    """
    (2.4) Check the validity of a service ticket. [CAS 1.0]

    When both ``service`` and ``ticket`` are provided, this view
    responds with a plain-text response indicating a ``ServiceTicket``
    validation success or failure. Whether or not the validation
    succeeds, the ``ServiceTicket`` is consumed, rendering it invalid
    for future authentication attempts.

    If ``renew`` is specified, validation will only succeed if the
    ``ServiceTicket`` was issued from the presentation of the user's
    primary credentials, not from an existing single sign-on session.
    """
    def get(self, request, *args, **kwargs):
        service = request.GET.get('service')
        ticket = request.GET.get('ticket')
        renew = to_bool(request.GET.get('renew'))

        try:
            st, attributes, pgt = validate_service_ticket(service, ticket, renew=renew)
            content = "yes\n%s\n" % st.user.get_username()
        except ValidationError:
            content = "no\n\n"
        return HttpResponse(content=content, content_type='text/plain')


class ServiceValidateView(NeverCacheMixin, CasResponseMixin, View):
    """
    (2.5) Check the validity of a service ticket. [CAS 2.0]

    When both ``service`` and ``ticket`` are provided, this view
    responds with an XML-fragment response indicating a
    ``ServiceTicket`` validation success or failure. Whether or not
    validation succeeds, the ticket is consumed, rendering it invalid
    for future authentication attempts.

    If ``renew`` is specified, validation will only succeed if the
    ``ServiceTicket`` was issued from the presentation of the user's
    primary credentials, not from an existing single sign-on session.

    If ``pgtUrl`` is specified, the response will include a
    ``ProxyGrantingTicket`` if the proxy callback URL has a valid SSL
    certificate and responds with a successful HTTP status code.
    """
    response_class = ValidationResponse

    def get_context_data(self, **kwargs):
        service = self.request.GET.get('service')
        ticket = self.request.GET.get('ticket')
        pgturl = self.request.GET.get('pgtUrl')
        renew = to_bool(self.request.GET.get('renew'))

        try:
            st, attributes, pgt = validate_service_ticket(service, ticket, pgturl=pgturl, renew=renew)
            return {'ticket': st, 'pgt': pgt, 'attributes': attributes, 'error': None}
        except ValidationError as e:
            logger.warning("%s %s" % (e.code, e))
            return {'ticket': None, 'error': e}


class ProxyValidateView(NeverCacheMixin, CasResponseMixin, View):
    """
    (2.6) Perform the same validation tasks as ServiceValidateView and
    additionally validate proxy tickets. [CAS 2.0]

    When both ``service`` and ``ticket`` are provided, this view
    responds with an XML-fragment response indicating a ``ProxyTicket``
    or ``ServiceTicket`` validation success or failure. Whether or not
    validation succeeds, the ticket is consumed, rendering it invalid
    for future authentication attempts.

    If ``renew`` is specified, validation will only succeed if the
    ``ServiceTicket`` was issued from the presentation of the user's
    primary credentials, not from an existing single sign-on session.

    If ``pgtUrl`` is specified, the response will include a
    ``ProxyGrantingTicket`` if the proxy callback URL has a valid SSL
    certificate and responds with a successful HTTP status code.
    """
    response_class = ValidationResponse

    def get_context_data(self, **kwargs):
        service = self.request.GET.get('service')
        ticket = self.request.GET.get('ticket')
        pgturl = self.request.GET.get('pgtUrl')
        renew = to_bool(self.request.GET.get('renew'))

        try:
            if not ticket or ticket.startswith(ProxyTicket.TICKET_PREFIX):
                # If no ticket parameter is present, attempt to validate it
                # anyway so the appropriate error is raised
                pt, attributes, pgt, proxies = validate_proxy_ticket(service, ticket, pgturl=pgturl)
                return {'ticket': pt, 'pgt': pgt, 'attributes': attributes, 'proxies': proxies, 'error': None}
            else:
                st, attributes, pgt = validate_service_ticket(service, ticket, pgturl=pgturl, renew=renew)
                return {'ticket': st, 'pgt': pgt, 'attributes': attributes, 'proxies': None, 'error': None}
        except ValidationError as e:
            logger.warning("%s %s" % (e.code, e))
            return {'ticket': None, 'error': e}


class ProxyView(NeverCacheMixin, CasResponseMixin, View):
    """
    (2.7) Provide proxy tickets to services that have acquired proxy-
    granting tickets. [CAS 2.0]

    When both ``pgt`` and ``targetService`` are specified, this view
    responds with an XML-fragment response indicating a
    ``ProxyGrantingTicket`` validation success or failure. If
    validation succeeds, a ``ProxyTicket`` will be created and included
    in the response.
    """
    response_class = ProxyResponse

    def get_context_data(self, **kwargs):
        pgt = self.request.GET.get('pgt')
        target_service = self.request.GET.get('targetService')

        try:
            pt = validate_proxy_granting_ticket(pgt, target_service)
            return {'ticket': pt, 'error': None}
        except ValidationError as e:
            logger.warning("%s %s" % (e.code, e))
            return {'ticket': None, 'error': e}


class SamlValidateView(NeverCacheMixin, View):
    """
    (4.2) Check the validity of a service ticket provided by a
    SAML 1.1 request document provided by a HTTP POST. [CAS 3.0]
    """
    response_class = SamlValidationResponse
    content_type = 'text/xml'

    def post(self, request, *args, **kwargs):
        context = self.get_context_data(**kwargs)
        return self.render_to_response(context)

    def render_to_response(self, context):
        return self.response_class(context, content_type=self.content_type)

    def get_context_data(self, **kwargs):
        target = self.request.GET.get('TARGET')

        assert defused_etree, '/samlValidate endpoint requires defusedxml to be installed'

        try:
            root = defused_etree.parse(self.request, forbid_dtd=True).getroot()
            ticket = root.find('.//{urn:oasis:names:tc:SAML:1.0:protocol}AssertionArtifact').text
        except (defused_etree.ParseError, ValueError, AttributeError):
            ticket = None

        try:
            st, attributes, pgt = validate_service_ticket(target, ticket, require_https=True)
            return {'ticket': st, 'pgt': pgt, 'attributes': attributes, 'error': None}
        except ValidationError as e:
            logger.warning("%s %s" % (e.code, e))
            return {'ticket': None, 'error': e}

希望会有所帮助。

答案 3 :(得分:1)

@Override
public boolean onCreateOptionsMenu(Menu menu)
{
    getMenuInflater().inflate(R.menu.main_menu, menu);
    MenuItem searchItem = menu.findItem(R.id.action_search);
    searchView = (SearchView) MenuItemCompat.getActionView(searchItem);


    searchView.setOnQueryTextFocusChangeListener(new View.OnFocusChangeListener()
    {
        @Override
        public void onFocusChange(View v, boolean newViewFocus)
        {
            if (!newViewFocus)
            {
                //Collapse the action item.
                searchItem.collapseActionView();
                //Clear the filter/search query.
                myFilterFunction("");
            }
        }
    });

    return super.onCreateOptionsMenu(menu);
}