AppBarLayout CollapsingToolbar 如何在 EditText 单击时禁用展开?

AppBarLayout CollapsingToolbar how to disable expand on EditText click?

在我的测试应用程序中,我禁用 AppBarLayout 折叠时的扩展(通过滚动 RecycleView)。我通过将 addOnOffsetChangedListener 添加到 AppBarLayout 来做到这一点。 但是,当我单击 EditText 时,它会再次展开,但我不希望它展开。 单击 EditText 时如何禁用 AppBarLayout 的展开?

我把全部代码放上来了,大家可以copy/paste代码,新建项目,快速测试一下。

这是 .gif 的样子

这里是XML代码:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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="match_parent"
    android:orientation="vertical">


    <android.support.design.widget.AppBarLayout
        android:id="@+id/app_bar_layout"
        android:layout_width="match_parent"
        android:layout_height="400dp"
        android:fitsSystemWindows="true"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">



        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:expandedTitleTextAppearance="@android:color/transparent"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scaleType="fitXY"
                android:src="@drawable/beachcroatia"/>

        </android.support.design.widget.CollapsingToolbarLayout>


    </android.support.design.widget.AppBarLayout>



    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycleView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginBottom="?attr/actionBarSize"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />



    <LinearLayout
        android:id="@+id/messages_linear_layout"
        android:layout_width="match_parent"
        android:layout_height="58dp"
        android:layout_gravity="bottom"
        android:background="#E1F5FE"
        android:orientation="horizontal"
        tools:layout_editor_absoluteY="453dp">



        <EditText
            android:id="@+id/editText_messageBox"
            android:layout_width="0dp"
            android:layout_height="40dp"
            android:layout_alignParentBottom="true"
            android:layout_gravity="center"
            android:layout_weight="0.85"
            android:hint="Enter a message"/>

        <ImageView
            android:id="@+id/messages_sendArrow"
            android:layout_width="0dp"
            android:layout_height="30dp"
            android:layout_gravity="center"
            android:layout_weight="0.15"
            android:src="@drawable/ic_send_message_" />

    </LinearLayout>

</android.support.design.widget.CoordinatorLayout>

这是完整的 MainActivity 代码:

public class MainActivity extends AppCompatActivity {

    private RecyclerView mRecyclerChat;
    private AdapterChat mAdapterChat;
    CollapsingToolbarLayout collapsingToolbarLayout;
    AppBarLayout appBarLayout;
    ImageView sendMessageImageViewButton;
    EditText editTextMessage;

    private List<Message> messagesList;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        collapsingToolbarLayout = findViewById(R.id.collapsing_toolbar);
        appBarLayout = findViewById(R.id.app_bar_layout);
        sendMessageImageViewButton = findViewById(R.id.messages_sendArrow);
        editTextMessage = findViewById(R.id.editText_messageBox);

        messagesList = new ArrayList<>();
        messagesList.addAll(getMessagesList());


        mRecyclerChat = findViewById(R.id.recycleView);
        LinearLayoutManager manager = new LinearLayoutManager(this);
        mRecyclerChat.setLayoutManager(manager);
        mAdapterChat = new AdapterChat(this, messagesList);
        mRecyclerChat.setAdapter(mAdapterChat);

        //move to the last item in recycleview
        mRecyclerChat.getLayoutManager().scrollToPosition(mAdapterChat.getMessagesObekt().size() - 1);

        editTextMessage.requestFocus();



        getWindow().setSoftInputMode(
                WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);


        appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
            @Override
            public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
                if (Math.abs(verticalOffset) == appBarLayout.getTotalScrollRange()) {
                    // Collapsed
                    Toast.makeText(MainActivity.this, "Collapsed", Toast.LENGTH_SHORT).show();

                    // disable expanding
                    AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) collapsingToolbarLayout.getLayoutParams();
                    params.setScrollFlags(0);

                } else if (verticalOffset == 0) {
                    Toast.makeText(MainActivity.this, "Extend", Toast.LENGTH_SHORT).show();
                    // Expanded
                } else {
                    // Somewhere in between
                }
            }
        });

       

      


        //sending new message and updating recycleview
        sendMessageImageViewButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "Message Send", Toast.LENGTH_SHORT).show();
                mAdapterChat.updateLastMessage(new Message(editTextMessage.getText().toString()));
                editTextMessage.getText().clear();
                mRecyclerChat.getLayoutManager().scrollToPosition(mAdapterChat.getMessagesObekt().size() - 1);
            }
        });
    }



    //ading some items to a list
    private List<Message> getMessagesList() {
        List<Message> mMessages = new ArrayList<>();

        for (int i = 0; i < 200; i++) {
            mMessages.add(new Message("message " + i));
        }

        return mMessages;
    }
}

这是我的消息 class 我在其中添加了虚拟数据以显示在 RecycleView

public class Message {
    private String message;

    public Message(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

这是 RecycleView 适配器代码:

package com.example.petar.collapsingtolbartestiramo;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

public class AdapterChat extends RecyclerView.Adapter<AdapterChat.ChatHolder> {
    private LayoutInflater mInflater;
    private List<Message> messagesObekt;

    public AdapterChat(Context context, List<Message> listOfMassages) {
        mInflater = LayoutInflater.from(context);
        messagesObekt = new ArrayList<>();
        messagesObekt.addAll(listOfMassages);
        notifyDataSetChanged();
    }

    public void updateChat(List<Message> porukeObjekt){
        this.messagesObekt.addAll(porukeObjekt);
        notifyDataSetChanged();
    }
    public void updateLastMessage(Message porukeObjekt) {
        this.messagesObekt.add(porukeObjekt);
        //notifyDataSetChanged();
        notifyItemInserted(messagesObekt.size());
    }

    public List<Message> getMessagesObekt() {
        return messagesObekt;
    }

    @Override
    public ChatHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = mInflater.inflate(R.layout.list_message, parent, false);
        ChatHolder holder = new ChatHolder(view, messagesObekt);
        return holder;
    }

    @Override
    public void onBindViewHolder(ChatHolder holder, int position) {
        holder.textViewMessage.setText(messagesObekt.get(position).getMessage());
    }

    @Override
    public int getItemCount() {
        return messagesObekt.size();
    }



    public static class ChatHolder extends RecyclerView.ViewHolder {

        TextView textViewMessage;

        public ChatHolder(View itemView, List<Message> messagesObekt) {
            super(itemView);

            textViewMessage = itemView.findViewById(R.id.rv_message);
        }
    }
}

这是 RecycleView 项目 XML 代码 (list_message.xml)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="5dp"
    android:orientation="vertical">
    <TextView
        android:id="@+id/rv_message"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Poruka Ovdje"
        android:textSize="14sp"/>

</LinearLayout>

:

编辑

我尝试将焦点侦听器添加到 EditText,但这没有帮助。这是我尝试的方式:

     editTextMessage.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if(hasFocus){
                    appBarLayout.setExpanded(false);
                    AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) collapsingToolbarLayout.getLayoutParams();
                    params.setScrollFlags(0);
                }
            }
        });

我已经找到答案了。我不知道是最好的解决方案,但效果很好。如果有人有更好的解决方案,欢迎留言。

所以,我所做的是在单击 EditTextEditText 获得焦点时将整个 AppBarLayout 参数设置为 0。 所以,当 EditText 被点击时, AppBarLayout 仍然存在,但是现在他的高度为 0 并且不可见。

这样做的技巧:

 //Collaps AppBarLayout
    public void collapsAppBarLayout(){
        CoordinatorLayout.LayoutParams params =(CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
        params.height = 0; // setting new param height to 0
        //setting params to appbarLayout (now AppBarLayout is 0)
        appBarLayout.setLayoutParams(params);
        appBarLayout.setExpanded(false);
    }

此外,如果您想要扩展选项,您需要保存先前参数的高度,然后再次添加该高度。

所以,这是我如何完成的代码: 首先,当我滚动 RecycleView 时,我使用 addOnOffsetChangedListener 禁用 appBarLayout 的扩展。但是我也保存参数高度以备将来使用。

int sizeParams; //save params height 


appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
            @Override
            public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
                if (Math.abs(verticalOffset) == appBarLayout.getTotalScrollRange()) {
                    // Collapsed
                    Toast.makeText(MainActivity.this, "Collapsed", Toast.LENGTH_SHORT).show();
                    // disable expanding and scroll
                    AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) collapsingToolbarLayout.getLayoutParams();
                    params.setScrollFlags(0);
                    //saving height for future use
                    sizeParams =  params.height;
                } else if (verticalOffset == 0) {
                    Toast.makeText(MainActivity.this, "Extend", Toast.LENGTH_SHORT).show();
                    // Expanded
                } else {
                    // Somewhere in between
                }
            }
        });

现在我制作这 2 个方法,当我需要时调用 expand/collaps。

   //Collaps AppBarLayout
    public void collapsAppBarLayout(){
        CoordinatorLayout.LayoutParams params =(CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
        sizeParams =  params.height;//save params height for future use
        params.height = 0; // setting new param height to 0
        //setting params to appbarLayout (now AppBarLayout is 0
        appBarLayout.setLayoutParams(params);
        appBarLayout.setExpanded(false);
    }
    //Expand AppBarLayout
    public void expandAppBarLayout(){
        CoordinatorLayout.LayoutParams params =(CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
        params.height = 3*sizeParams; // HEIGHT
        appBarLayout.setLayoutParams(params); //add height to appbarlayout
        //enable scroll and expand 
        AppBarLayout.LayoutParams params1 = (AppBarLayout.LayoutParams) collapsingToolbarLayout.getLayoutParams();
        params1.setScrollFlags(1);
        appBarLayout.setExpanded(true);//expand
    }

I do not know is the best solution, but it works nice. If someone has better solution, feel free to write it.

确实有更好、更干净、更简单的解决方案。 导致这个“问题”的罪魁祸首其实是Google在AppBarLayout.ScrollingViewBehavior里面添加的一个特性。这是您通过 app:layout_behavior="@string/appbar_scrolling_view_behavior" 设置的那个。在 class 中,只要显示键盘,onRequestChildRectangleOnScreen 就会调用 setExpanded(false, !immediate)。您只需覆盖此方法和 return false 即可禁用此默认行为。将此 class 添加到您的项目中:

import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.coordinatorlayout.widget.CoordinatorLayout;

import com.google.android.material.appbar.AppBarLayout;

public class FixedScrollingViewBehavior extends AppBarLayout.ScrollingViewBehavior {

    public FixedScrollingViewBehavior() {
        super();
    }

    public FixedScrollingViewBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onRequestChildRectangleOnScreen(@NonNull CoordinatorLayout parent,
            @NonNull View child, @NonNull Rect rectangle, boolean immediate) {
        return false;
    }
}

然后通过将 app:layout_behavior="@string/appbar_scrolling_view_behavior" 更改为 app:layout_behavior="your.source.package.FixedScrollingViewBehavior" 来使用这个新的 class。