In my application I have an ImageView that gets with buttom alignment, in a RelativeLayout which is the root view of the Layout:
The problem is that when the keyboard is opened, it goes up together:
I tried to fix it by putting it in Manifest: `android:windowSoftInputMode="stateVisible|adjustPan",
It works, the problem is that the FloatingButton stops scrolling too, is there any way to make ImageView only "locked" down when the keyboard opens?
The xml looks like this:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:layout_alignParentBottom="true"
app:srcCompat="#drawable/ic_rodape"/>
<ScrollView........../>
<android.support.design.widget.FloatingActionButton
android:id="#+id/ok"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_margin="8dp"
app:backgroundTint="#color/colorPrimary"
app:srcCompat="#drawable/back"/>
</RelativeLayout>
Instead of using android:windowSoftInputMode="stateVisible|adjustPan" use this to hide specific views RelativeLayout rootView = (RelativeLayout) findViewById(R.id.root)
rootView is just a view pointing to your root view in this case a relative layout(give an id to your Relative layout)
rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
Rect r = new Rect();
rootView.getWindowVisibleDisplayFrame(r);
int heightDiff = rootView.getRootView().getHeight() - (r.bottom - r.top);
if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
//when the keyboard is up...
view_one.setVisibility(View.GONE);
}else{
//when the keyboard is down...
view_one.setVisibility(View.VISIBLE);
}
}
});
Thanks to answers here and here
Related
I've inflated a PopupWindow using the method .showAsDropDown() however I'm not sure why It's not allowing me to shift it right or left. It works perfectly fine when shifting up and down.
public class TestWindow extends PopupWindow {
private final Context context;
public TestWindow (Context context) {
super(context);
this.context = context;
setupView();
}
private void setupView() {
View view = LayoutInflater.from(context)
.inflate(R.layout.popup_window_wallet_options, null);
ButterKnife.bind(this, view);
setOutsideTouchable(true);
setFocusable(true);
setBackgroundDrawable(ContextCompat.getDrawable(context, R.drawable.bgr_menu_clear_wallet));
setElevation(SpacingUtils.convertIntToDP(context, 4));
setContentView(view);
}
}
PopupWindow popupWindow = new TestWindow(context);
popupWindow.showAsDropDown(anchorButton, 50, -30);
Shifting the menu up by 30 works perfectly fine, but also I'm trying to shift it towards the left and it's not working. What am I doing incorrectly?
Note:
I've already tried it with 50 and -50 so I'm at lost why it's not moving horizontally
My R.layout.popup_window_wallet_options
<?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:orientation="vertical"
android:background="#drawable/bgr_menu_clear_wallet">
<TextView
android:id="#+id/tv_wallet_qr"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:foreground="?attr/selectableItemBackground"
android:padding="6dp"
android:text="Wallet QR"
android:textColor="#color/black" />
<TextView
android:id="#+id/tv_clear_wallet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:foreground="?attr/selectableItemBackground"
android:padding="6dp"
android:text="Clear wallet"
android:textColor="#color/black" />
</LinearLayout>
Disclaimer: This is not a direct fix to showAsDropDown(), but it could be a workaround with showAtLocation().
By using the window decorView as the anchorView, and accumulating the actual anchorView location to x & y shift values.
int[] anchorView = new int[2];
anchorButton.getLocationInWindow(anchorView); // anchor button location in the window
popupWindow.showAtLocation(getWindow().getDecorView(), Gravity.NO_GRAVITY,
anchorView[0] + 50,
anchorView[1] + anchorButton.getHeight() -30);
UPDATE:
The anchorButton is an ImageView. Can you post your code + xml for it
Nothing special than yours.
This is the popup window layout
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="test clear"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
The activity just has a button as the anchorView:
And calling it:
Button button = findViewById(R.id.button);
PopupWindow popupWindow = new TestWindow(MainActivity.this);
popupWindow.showAsDropDown(button, 50, -30);
I have a RecycleView in which I visualize some text. The text is entered through an EditText view in the bottom. The RecycleView contains a TextView which is has the text centered.
I have also a function that detects if the keyboard is visualised. When the keyboard is visualised, then some layout parameters are changed so that the EditText looks good. I also have a smooth scroll to the last position of the RecycleView.
When I reopen the keyboard again, the text is first drawn to the left of the screen. If I swipe, the text is re-aligned to center. That is very disturbing and I always want the text to be centered. I probably miss something when changing the parameters of the layouts.
KeyBoard openedListener:
// Function to see of keyboard is opened or not.
private void detectKeyBoard(){
final ConstraintLayout rootView = findViewById(R.id.activity_root);
rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
float heightDiff = rootView.getRootView().getHeight() - rootView.getChildAt(0).getHeight();
if (!isRefSet){
refDiff = heightDiff;
isRefSet = true;
}
if (heightDiff > refDiff) {
LinearLayout.LayoutParams params = new
LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
0);
params.weight = wRSmall;
mRecyclerView.setLayoutParams(params);
LinearLayout.LayoutParams eParams = new
LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
0);
eParams.weight = wESmall;
mLinearInput.setLayoutParams(eParams);
if (mAdapter.getItemCount() > 0) {
mRecyclerView.smoothScrollToPosition(mAdapter.getItemCount() - 1);
}
} else {
LinearLayout.LayoutParams params = new
LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
0);
params.weight = wRStart;
mRecyclerView.setLayoutParams(params);
LinearLayout.LayoutParams eParams = new
LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
0);
eParams.weight = wEStart;
mLinearInput.setLayoutParams(eParams);
if (mAdapter.getItemCount() > 0) {
mRecyclerView.smoothScrollToPosition(mAdapter.getItemCount() - 1);
}
}
}
});
}
xml for RecycleView:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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:id="#+id/activity_root"
tools:context="com.example.erikbylow.autoflash.TranslateActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/translate_linear"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.9"
android:scrollbars="vertical"
android:layout_gravity="center_horizontal"
android:id="#+id/translate_recycle"
android:background="#android:color/holo_blue_bright" />
<LinearLayout
android:layout_width="match_parent"
android:id="#+id/linear_input"
android:layout_height="0dp"
android:layout_weight="0.1"
android:orientation="horizontal">
<EditText
android:layout_width="0dp"
android:layout_weight="0.75"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:singleLine="true"
android:id="#+id/source_input"
android:hint="Type text to translate"/>
<Button
android:layout_height="match_parent"
android:layout_width="0dp"
android:layout_weight="0.25"
android:layout_alignRight="#+id/source_input"
android:text="Translate"
android:clickable="true"
android:onClick="startTranslate"
android:background="#android:color/holo_green_dark"/>
</LinearLayout>
</LinearLayout>
TextView for Adapter:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:textSize="#dimen/active_text_size"
android:id="#+id/adapter_textview"/>
After swiping it is re-aligned:
EDIT: It did not work to remove android:layout_gravity="center_horizontal" in the recycle xml part.
Further, if the screen is full without the keyboard being opened, the text is moved to the right:
Can you comment the detectKeyBoard() function? Just to check if the same problem exists or not?
Just a guess -
I see that you are creating a new LayoutParams object and assign it to your mRecyclerView and mLinearInput.
As far as I know, this new LayoutParam object will replace what you have set in XML, including layout_gravity, layout_weight, etc.
Try getting existing LayoutParams from mRecyclerView and mLinearInput, and modify their values instead.
Cannot advise much because I do not really understand the reason behind resetting layout params in your case.
So View.getTop() is, as per the docs:
Top position of this view relative to its parent.
I have the following layout:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/root"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.scrollviewtest1.MainActivity">
<LinearLayout
android:id="#+id/scroll_container"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.example.scrollviewtest1.MyTextView
android:id="#+id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/large_text" />
<TextView
android:id="#+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
</LinearLayout>
</ScrollView>
I am checking for getTop() for LinearLayout as I scroll up and down and getTop() always returns 0. Shouldn't it change as it moves up and down relative to its parent?.
How I checked it?
I stored reference to the LinearLayout inside the child TextView and called invalidate() every time there was scrolling:
ScrollView root = ((ScrollView) findViewById(R.id.root));
root.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
#Override
public void onScrollChanged() {
textView.invalidate();
}
});
and checked inside the onDraw() call of the child TextView
Try this way :
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
int top = view.getTop();
}
}, 300);// delay times in milliseconds
You can set delay time as per your requirement.
To get the LinearLayout scrolled position call myScrollView.getScrollY();
getTop(); returns what you entered as marginTop in your xml layout and it not varies when the thing is scrolled, to know the actual current position you need to take in account getScrollY(); too
I have layout with scrollView as below :
<ScrollView
android:id="#+id/scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:id="#+id/transparentLayout"
android:layout_width="match_parent"
android:layout_height="150dp"
android:background="#android:color/transparent"
android:orientation="vertical" >
</LinearLayout>
... other views
</ScrollView>
I want to detect if the transparentLayout (LinearLayout) is scrolled out of the screen.
I solved it in this fashion:
scrollView.getViewTreeObserver().addOnScrollChangedListener(new OnScrollChangedListener() {
#Override
public void onScrollChanged() {
Rect scrollBounds = new Rect();
scrollView.getHitRect(scrollBounds);
if (layout.getLocalVisibleRect(scrollBounds)) {
// if layout even a single pixel, is within the visible area do something
} else {
// if layout goes out or scrolled out of the visible area do something
}
}
});
I have a ListView and the last list item contains EditText:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<RelativeLayout
android:id="#+id/contentLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="30dp"
android:orientation="vertical" >
<ImageView
android:id="#+id/test"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignRight="#+id/messageEditText"
android:layout_below="#+id/messageEditText"
android:layout_marginRight="14dp"
android:src="#drawable/test" />
<EditText
android:id="#+id/messageEditText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_toLeftOf="#+id/sendImageButton"
android:ems="10"
android:gravity="top"
android:hint="#string/messageEditText"
android:inputType="textMultiLine"
android:minHeight="55dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="10dp" />
<ImageButton
android:id="#+id/sendImageButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="#id/messageEditText"
android:layout_alignParentRight="true"
android:layout_alignTop="#id/messageEditText"
android:adjustViewBounds="true"
android:maxHeight="55dp"
android:maxWidth="55dp"
android:padding="12dp"
android:scaleType="centerInside"
android:src="#drawable/sendmessage" />
</RelativeLayout>
</RelativeLayout>
Half of the EditText is hidden. I also can't scroll ListView. Any solution?
Solution was to set an android:softInputMode attribute to adjustResize in Manifest and put layout(not list item layout) inside a ScrollView.
I Had a similar issue, then i used android:windowSoftInputMode="adjustResize|stateHidden" as mentioned here.. It works very well for me..
From my early days as a Android Developer I struggled with the virtual keyboard. I am amazed that Android is still not giving an elegant and clear solution for this.
So here is the Workaround that will put this mess behind you. it will work without the ScrollView workaround or giving away your full screen flag.
Add this awesome Library to your gradle file:
compile'net.yslibrary.keyboardvisibilityevent:keyboardvisibilityevent:1.0.1'
Make sure your activity has the following keyboard settings:
android:windowSoftInputMode="adjustResize"
wrap your EditText with a vertical LinearLayout and add a View with Visibility of Gone:
<com.ylimitapp.ylimitadmin.views.NormalFontEditText
android:id="#+id/input_et"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textCapSentences|textMultiLine"
android:imeOptions="actionSend"
android:paddingStart="20dp"
android:paddingEnd="40dp"
android:paddingTop="10dp"
android:maxHeight="120dp"
android:adjustViewBounds= "true"
android:scrollHorizontally="false"
android:textColorHint="#7b7b7b"
android:hint="#string/type_your_message"
android:background="#drawable/msg_inputfield_bg"
android:textColor="#color/black_text_color"
android:textSize="15.33sp"
/>
<View
android:id="#+id/keyboard_view"
android:layout_width="match_parent"
android:layout_height="20dp"
android:visibility="gone"
/>
</LinearLayout>
calculate the screen size so you can calculate the height of the view that pushes the EditText:
private void storeScreenHeightForKeyboardHeightCalculations() {
Rect r = new Rect();
View rootview = getActivity().getWindow().getDecorView();
rootview.getWindowVisibleDisplayFrame(r);
mOriginalScreenHeight = r.height();
Rect rectangle = new Rect();
Window window = getActivity().getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectangle);
int statusBarHeight = rectangle.top;
int contentViewTop =
window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
int titleBarHeight= contentViewTop - statusBarHeight;
if (titleBarHeight == 0) {
mOriginalScreenHeight -= (24 * Utils.getDensity(getContext()));
}
}
Add a Listener for keyboard open and close event and then set the height of the View below the EditText on runtime so we will set the height properly on any device and custom keyboards. then simply make it Visible when the Keyboard is Open:
private void addkeyBoardlistener() {
KeyboardVisibilityEvent.setEventListener(
getActivity(),
new KeyboardVisibilityEventListener() {
#Override
public void onVisibilityChanged(boolean isOpen) {
if (isOpen) {
Rect r = new Rect();
View rootview = getActivity().getWindow().getDecorView(); // this = activity
rootview.getWindowVisibleDisplayFrame(r);
int keyboardHeight = (mOriginalScreenHeight - r.height());
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) keyboard_view.getLayoutParams();
params.height = (int) ((keyboardHeight + 5 * Utils.getDensity(getContext())));
keyboard_view.setLayoutParams(params);
keyboard_view.setVisibility(View.VISIBLE);
} else {
keyboard_view.setVisibility(View.GONE);
}
}
});
}
This is the result:
Disable the keyboard on window startup
this .getWindow().setSoftInputMode(WindowManager.LayoutParams. SOFT_INPUT_STATE_ALWAYS_HIDDEN );
Set an android:softInputMode attribute for your Activity element in your Manifest.
See the Manifest documentation for a full list of valid values and their effect. The ones of particular interest to you will likely be adjustPan and adjustResize.
Add this in the manifest like so:
<activity
android:name="your_activity_name"
android:windowSoftInputMode="adjustResize"
android:theme="#style/Theme.AppCompat.DayNight.NoActionBar" />
Then add paddingBottom="20dp" in your layout and editText.