'Show RecyclerView/PopupWIndow by anchoring below or above edittext depending on where the cursor is and depending on screen available height

I am trying to display @ user mentions like facebook or twitter. I am able to implement this functionality. But i have a ui problem.

If edittext is at the bottom of the screen i need to show suggestion in recyclerview at the top.(above edittext cursor)

If edittext is at the top of the screen i need to show suggestion in recycelrview at the bottom (below edittext cursor)

What have i tried?

I have used recyclerview that is constrained below edittext

Problem

When soft keyboard opens it covers the recyclerview. This happens when edittext cursor is at the bottom.

enter image description here

How can i fix this using existing recyclerview itself?.

When edittext cursor is at the top see suggestions are shown below properly.

enter image description here

Code

<?xml version="1.0" encoding="utf-8"?>
<layout 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">

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:textStyle="bold"
            android:textSize="16sp"
            android:textColor="@color/black"
            android:fontFamily="@font/source_sans_pro"
            android:id="@+id/titleHeader"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="16dp"
            android:layout_marginTop="16dp"
            android:text="@string/create_feed_post"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.0"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <View
            android:id="@+id/line"
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:layout_marginTop="16dp"
            android:background="#c8c8c8"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/titleHeader" />


        <com.linkedin.android.spyglass.ui.MentionsEditText
            android:padding="8dp"
            android:id="@+id/mentionsEditText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:maxHeight="300dp"
            android:layout_marginStart="16dp"
            android:layout_marginTop="16dp"
            android:layout_marginEnd="16dp"
            android:background="@null"
            android:gravity="start|top"
            android:hint="Share team wins or recognize colleague for a job well done"
            android:inputType="textMultiLine"
            android:minHeight="50dp"
            android:paddingStart="15dp"
            android:paddingEnd="15dp"
            android:textSize="16sp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="1.0"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/line">

        </com.linkedin.android.spyglass.ui.MentionsEditText>

        <ImageView
            android:id="@+id/preview"
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:layout_marginStart="16dp"
            android:layout_marginTop="16dp"
            android:visibility="visible"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.0"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/mentionsEditText" />

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/list"
            android:layout_width="0dp"
            android:layout_height="250dp"
            android:layout_marginStart="16dp"
            android:layout_marginEnd="16dp"
            android:elevation="5dp"
            android:orientation="vertical"
            android:overScrollMode="never"
            android:scrollbarStyle="outsideOverlay"
            android:scrollbars="none"
            android:visibility="gone"
            app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/mentionsEditText" />

        <View
            android:id="@+id/line2"
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:layout_marginTop="8dp"
            android:background="#c8c8c8"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/preview" />


        <androidx.constraintlayout.widget.ConstraintLayout
            android:id="@+id/optionsContainer"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginStart="16dp"
            android:layout_marginTop="8dp"
            android:layout_marginEnd="16dp"
            android:layout_marginBottom="16dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/line2">

            <ImageView
                android:id="@+id/visibility"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="16dp"
                android:src="@drawable/toggle_comment"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintStart_toEndOf="@+id/attach"
                app:layout_constraintTop_toTopOf="parent" />

            <ImageView
                android:id="@+id/attach"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="16dp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                app:srcCompat="@drawable/ic_upload_image" />

            <Button
                android:id="@+id/done"
                android:layout_width="0dp"
                android:layout_height="60dp"
                android:layout_marginStart="32dp"
                android:text="@string/post"
                android:textAllCaps="false"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="@id/visibility"
                app:layout_constraintTop_toTopOf="parent" />

        </androidx.constraintlayout.widget.ConstraintLayout>

        <ImageView
            android:id="@id/cancel"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginEnd="16dp"
            app:layout_constraintBottom_toBottomOf="@+id/titleHeader"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="@+id/titleHeader"
            app:srcCompat="@drawable/ic_close"
            app:tint="@color/black" />

        <FrameLayout
            android:visibility="gone"
            android:elevation="5dp"
            android:id="@+id/container"
            app:layout_constraintBottom_toTopOf="@+id/preview"
            app:layout_constraintEnd_toEndOf="@+id/preview"
            app:layout_constraintTop_toTopOf="@+id/preview"
            android:layout_width="20dp"
            android:layout_height="20dp">
            <com.mikhaellopez.circleview.CircleView
                app:cv_border_width="1dp"
                app:cv_border_color="#EAEAEA"
                app:cv_border="true"
                app:cv_color="@color/white"
                android:layout_gravity="center"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>

            <ImageView
                android:layout_gravity="center"
                android:id="@+id/removePreview"
                android:layout_width="15dp"
                android:layout_height="15dp"
                app:srcCompat="@drawable/ic_close"
                app:tint="#999999" />

        </FrameLayout>
        
    </androidx.constraintlayout.widget.ConstraintLayout>
    </ScrollView>
</layout>

Update: i tried using a pop up window. I am able to show above or below a view depending on where the view is located. But there is still one problem with keyboard opening. The pop up comes over the keyboard when the edittext is at the bottom. The edittext moves up but popup window stays in same place

Update 2:

    if(anchor instanceof EditText) {
        EditText editText = (EditText) anchor;
        int pos = editText.getSelectionStart();
        Layout layout = editText.getLayout();
        int line = layout.getLineForOffset(pos);
        int baseline = layout.getLineBaseline(line);
        int ascent = layout.getLineAscent(line);
        float cursorx = layout.getPrimaryHorizontal(pos);
        cursory = baseline + ascent- editText.getScrollY();
        
    }



    final View contentView = view;

    final Rect windowRect = new Rect();
    contentView.getWindowVisibleDisplayFrame(windowRect);
    final int windowW = windowRect.width();
    final int windowH = windowRect.height();
    contentView.measure(
            makeDropDownMeasureSpec(getWidth(), windowW),
            makeDropDownMeasureSpec(getHeight(), windowH)
    );
    final int measuredW = contentView.getMeasuredWidth();
    final int measuredH = contentView.getMeasuredHeight();
    final int[] anchorLocation = new int[2];
    anchor.getLocationInWindow(anchorLocation);
    final int anchorBottom = anchorLocation[1] + anchor.getHeight();
    

      if (y + anchorBottom < 0) {
            y = -anchorBottom;
        } else  {
          y = (int) (y + cursory );

       }

And then

popupWindow.showAsDropDown(anchor, 0, y);

and the flag in manifest is

android:windowSoftInputMode="adjustResize"


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source