如何将软键盘隐藏在一个片段中?

我有一个 FragmentActivity使用一个 ViewPager服务几个片段。每个是一个 ListFragment与以下布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="8dp">
<ListView android:id="@id/android:list"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />


<EditText android:id="@+id/entertext"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>

当开始活动时,软键盘显示。为了补救这个问题,我在片段内部做了以下操作:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//Save the container view so we can access the window token
viewContainer = container;
//get the input method manager service
imm = (InputMethodManager)getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
. . .
}


@Override
public void onStart() {
super.onStart();


//Hide the soft keyboard
imm.hideSoftInputFromWindow(viewContainer.getWindowToken(), 0);
}

我从 onCreateView保存传入的 ViewGroup container参数,作为访问主活动的窗口令牌的一种方法。这运行没有错误,但键盘没有得到隐藏从 onStarthideSoftInputFromWindow调用。

最初,我尝试使用充气布局而不是 container,即:

imm.hideSoftInputFromWindow(myInflatedLayout.getWindowToken(), 0);

但这抛出了一个 NullPointerException可能是因为片段本身不是一个活动也没有唯一的窗口标记?

是否有办法在片段中隐藏软键盘,或者我应该在 FragmentActivity中创建一个方法并在片段中调用它?

115501 次浏览

If you add the following attribute to your activity's manifest definition, it will completely suppress the keyboard from popping when your activity opens. Hopefully this helps:

(Add to your Activity's manifest definition):

android:windowSoftInputMode="stateHidden"

As long as your Fragment creates a View, you can use the IBinder (window token) from that view after it has been attached. For example, you can override onActivityCreated in your Fragment:

@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getView().getWindowToken(), 0);
}

Exception for DialogFragment though, focus of the embedded Dialog must be hidden, instead only the first EditText within the embedded Dialog

this.getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);

Nothing but the following line of code worked for me:

getActivity().getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
    @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_my, container,
false);
someClass.onCreate(rootView);
return rootView;
}

Keep an instance of my root view in my class

View view;


public void onCreate(View rootView) {
view = rootView;

Use the view to hide the keyboard

 public void removePhoneKeypad() {
InputMethodManager inputManager = (InputMethodManager) view
.getContext()
.getSystemService(Context.INPUT_METHOD_SERVICE);


IBinder binder = view.getWindowToken();
inputManager.hideSoftInputFromWindow(binder,
InputMethodManager.HIDE_NOT_ALWAYS);
}

This code works for fragments:

getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);

Nothing of this worked on API27. I had to add this in the container of the layout, for me it was a ConstraintLayout:

<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="true"
android:focusableInTouchMode="true"
android:focusedByDefault="true">


//Your layout


</android.support.constraint.ConstraintLayout>

Use this static method, from anywhere (Activity / Fragment) you like.

public static void hideKeyboard(Activity activity) {
try{
InputMethodManager inputManager = (InputMethodManager) activity
.getSystemService(Context.INPUT_METHOD_SERVICE);
View currentFocusedView = activity.getCurrentFocus();
if (currentFocusedView != null) {
inputManager.hideSoftInputFromWindow(currentFocusedView.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
}catch (Exception e){
e.printStackTrace();
}
}

If you want to use for fragment just call hideKeyboard(((Activity) getActivity())).

this will be work in my case when in tabs i switch from one fragment to another fragments

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
try {
InputMethodManager mImm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
mImm.hideSoftInputFromWindow(getView().getWindowToken(), 0);
mImm.hideSoftInputFromWindow(getActivity().getCurrentFocus().getWindowToken(), 0);
} catch (Exception e) {
Log.e(TAG, "setUserVisibleHint: ", e);
}
}
}

Just add this line in you code:

getActivity().getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);

In Kotlin:

(activity?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager).hideSoftInputFromWindow(view?.windowToken,0)

This worked for me in Kotlin class

fun hideKeyboard(activity: Activity) {
try {
val inputManager = activity
.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
val currentFocusedView = activity.currentFocus
if (currentFocusedView != null) {
inputManager.hideSoftInputFromWindow(currentFocusedView.windowToken, InputMethodManager.HIDE_NOT_ALWAYS)
}
} catch (e: Exception) {
e.printStackTrace()
}


}

Use this code in any fragment button listener:

InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(getActivity().INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getActivity().getCurrentFocus().getWindowToken(), 0);

Use this:

Button loginBtn = view.findViewById(R.id.loginBtn);
loginBtn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(getActivity().INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
});

Kotlin code

val imm = requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(requireActivity().currentFocus?.windowToken, 0)

IN BEGINNING

in fragment, below code(use in onActivityCreated) force to hide keyboard in beginning:

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);


Objects.requireNonNull(getActivity()).getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
}

DURING FRAGMENT (if need)

and also if you have edittext or sth different needs keyboard, and wanna hide the keyboard when pressing outside the keyboard(in my case I have LinearLayout class in xml), first initialize the layout:

LinearLayout linearLayout;


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    

View view = inflater.inflate(R.layout.<your fragment xml>, container, false);


linearLayout= view.findViewById(R.id.linearLayout);
...
return view;
}

then, you need to below code(use in onViewCreated):

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {


linearLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view12) {
try {
InputMethodManager inputMethodManager = (InputMethodManager) Objects.requireNonNull(VideoFragment.this.getActivity()).getSystemService(INPUT_METHOD_SERVICE);
assert inputMethodManager != null;
inputMethodManager.hideSoftInputFromWindow(VideoFragment.this.getActivity().getCurrentFocus().getWindowToken(), 0);


} catch (Exception e) {
e.printStackTrace();
}
}
});


}

You can use two ways:

You can create a method inside fragment, but first you must create a View attribute and put the inflater result inside it before it returns in onCreateView:

1° Open your Fragment class. Create attribute

private View view;

2° assign the 'view' attribute the inflater in onCreateView

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
view = inflater.inflate(R.layout.your_activity_main, container, false);
return view;
}

3° create the method 'hideKeyboard'

public void hideKeyboard(Activity activity) {
try{
InputMethodManager inputManager = (InputMethodManager) activity
.getSystemService(view.getContext().INPUT_METHOD_SERVICE);
View currentFocusedView = activity.getCurrentFocus();
if (currentFocusedView != null) {
inputManager.hideSoftInputFromWindow(currentFocusedView.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
}catch (Exception e){
e.printStackTrace();
}
}

5° Now just call the method

    hideKeyboard(getActivity());

If that doesn't solve your problem, you can try passing the MainActivity class as an object to close the keyboard inside the Frament class

1° In YourClassActivity that you instantiated Fragment, create the method 'hideKeyboard'

public class YourClassActivity extends AppCompatActivity {
public static void hideKeyboard(Activity activity) {
InputMethodManager imm = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
//Find the currently focused view, so we can grab the correct window token from it.
View view = activity.getCurrentFocus();
//If no view currently has focus, create a new one, just so we can grab a window token from it
if (view == null) {
view = new View(activity);
}
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
}

2° Implement the 'Serializable' interface in your Activity that instantiates the Fragment

public class YourClassActivity extends AppCompatActivity implements Serializable {
...
}

3° When you instantiate the Frament in the Activity, you must pass the arguments to that Fragment, which will be the Activity class itself

Bundle bundle = new Bundle();
bundle.putSerializable("activity", this);
YourClassFragment fragment = new YourClassFragment();
fragment.setArguments(bundle);

4° Now let's go to your Fragment class. Create attribute view and activity.

private View view;
private Activity activity;

5° Assign the 'view' attribute the inflater in onCreateView. Here you will retrieve the Activity object that was passed as a parameter of this Fragment

    @Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
view = inflater.inflate(R.layout.your_activity_main, container, false);
activity = (Activity) getArguments().getSerializable("obj");
    

return view;
}

6° Now just call the method

hideKeyboard(activity);

Solution that worked for me in fragments:

fun hideKeyboard(){
val imm = requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(view?.windowToken, 0)
}

and in an activity:

fun hideKeyboard(){
val inputManager: InputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
inputManager.hideSoftInputFromWindow(currentFocus?.windowToken, InputMethodManager.SHOW_FORCED)
}

I did all steps but there is something missing I hide the keyboard in fragments with that method

fun hideKeyBoard(view: View) {
val inputManager =
requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
inputManager.hideSoftInputFromWindow(
view.windowToken,
SOFT_INPUT_STATE_ALWAYS_HIDDEN
)
}

but still when I open the fragment the keyboard open also after a lot of search I found the problem I must put those code in my xml layout root

android:focusable="true"
android:focusableInTouchMode="true"

Note: If you delete above method and just put the attributes in root layout, it will work fine.