How scroll while selecting/highlighting the text in TextView? - android

I have a FrameLayout with some children, MaterialTextView within a ScrollView and a Slider within a LinearLayout:
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true">
<ScrollView
android:id="#+id/scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:fillViewport="true"
android:scrollbars="none"
android:visibility="gone">
<com.google.android.material.textview.MaterialTextView
android:id="#+id/text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autoLink="all"
android:linksClickable="false"
android:textColor="#color/text"
android:textColorLink="#color/blue"
android:textIsSelectable="true"
android:textSize="18sp" />
</ScrollView>
<LinearLayout
android:id="#+id/linear_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center|bottom"
android:layout_margin="32dp"
android:background="#drawable/shape_inactive"
android:visibility="gone">
<com.google.android.material.slider.Slider
android:id="#+id/slider"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:stepSize="2.0"
android:valueFrom="14.0"
android:valueTo="30.0"
app:labelBehavior="floating"
app:labelStyle="#style/Slider.Tooltip"
app:thumbColor="#color/secondary"
app:tickColor="#color/secondary"
app:trackColorActive="#color/secondary"
app:trackColorInactive="#android:color/transparent" />
</LinearLayout>
</FrameLayout>
What I want to achieve/which issues I am facing:
I can select/highlight the text, but not scroll down/up when the bottom/top is reached.
The MaterialTextView recognizes any link such as Web, Emails, Phone numbers, but any touch on text, not on links, opens the link.
A User can call Slider, that appears right on the ScrollView/MaterialTextView. But a touch on ScrollView/MaterialTextView should hide the Slider.
How would I achieve that result, where all above use cases are working? Is that possible? Because, I tried different ways to deal with one or other issue listed above.

Related

How to put background shapes in ConstraintLayout?

I had nested LinearLayouts and after reading some doc I tried to switch to ConstraintLayout. But I did not find how to insert a view to just display a background.
So far I just set the background on the layout containing the items.
This is what the old nested structure looks like (with more nested items in other sub-layouts):
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#color/black"
android:gravity="center" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
... some margins and padding
android:background="#drawable/global_background" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_gravity="center"
android:background="#drawable/text_area_background" >
<TextView
android:id="#+id/Text1"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center" />
<TextView
android:id="#+id/Text2"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center" />
...
This way I was able to easily set a shape of my own as a background for the different groups of items I displayed.
How can I achieve the equivalent using ConstraintLayout?
I understand how I can constrain my items to get organized the same way, and how I could set the backgrounds to align with everything too. But how do I insert a simple background item?
I used ImageView to display my background and (hardly) found a way to assemble my items inside it.
One problem is that I get a warning Image without contentDescription.
<androidx.constraintlayout.widget.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:id="#+id/constraintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/black">
<ImageView
android:id="#+id/background"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="10dp"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="10dp"
android:layout_marginRight="10dp"
android:layout_marginBottom="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="2:5"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1.0"
app:srcCompat="#drawable/global_background" />
...
<Button
android:id="#+id/buttonValidate"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="10dp"
android:layout_marginLeft="10dp"
android:layout_marginTop="2dp"
android:layout_marginEnd="10dp"
android:layout_marginRight="10dp"
android:layout_marginBottom="8dp"
android:background="#drawable/green_button"
android:text="#string/validate"
app:layout_constraintBottom_toBottomOf="#+id/background"
app:layout_constraintDimensionRatio="15:6"
app:layout_constraintEnd_toEndOf="#+id/background"
app:layout_constraintStart_toStartOf="#+id/background"
app:layout_constraintTop_toBottomOf="#+id/upperButton" />
But I struggled to put another background inside (itself containing several TextView). My constraints were always messing one or the other... I ended up with a nested ConstraintLayout which is working fine, probably not the optimal solution but all my other attempts failed.

SoftKeyboard pushes all the views

I'm trying to make a chat layout. The problem is when I focus the EditText, softkeyboard appears and pushes everything up. I want it to push only bottom part with send instructions so that top (brown) header part and a recyclerview with messages are still visible. Something that facebook messenger app has. I tried putting "adjust pan, resize" and everything in manifest file, but it didn't work. Here is my default layout when nothing is in focus:
And this is when I press the EditText and keyboard appears and shifts everything up:
I can't see header anymore nor the message in recyclerView.
Basically I want all elements to stay visible at all times, so when Keyboard pushes up, header, messages and send are still visible to the user.
Here is my layout code:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:id="#+id/ll_profile"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_alignParentTop="true"
android:layout_marginBottom="10dp"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp">
<de.hdodenhof.circleimageview.CircleImageView
android:id="#+id/iv_profile"
android:layout_width="40dp"
android:layout_height="40dp"
android:src="#drawable/img_back" />
<TextView
android:id="#+id/tv_profile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="10dp" />
</LinearLayout>
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/ll_profile"
android:fillViewport="true"
android:isScrollContainer="false">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<View
android:id="#+id/view_line"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginEnd="10dp"
android:layout_marginStart="10dp"
android:background="#color/gray_light_trans" />
<LinearLayout
android:id="#+id/ll_send"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:weightSum="10">
<EditText
android:id="#+id/et_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="9"
android:hint="Message" />
<Button
android:id="#+id/btn_send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Send" />
</LinearLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/rv_chat"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="#id/ll_send"
android:layout_below="#id/view_line" />
</RelativeLayout>
</android.support.v4.widget.NestedScrollView>
use android:windowSoftInputMode="stateHidden" in your activity at manifest
The issue was that I was using a theme in my App activity that was fullscreen. When I removed fullscreen from main base theme, it's working.

Layout being measured twice, what could be the issue?

I am using the following layouts:
<merge
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<VideoView
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ProgressBar
android:visibility="invisible"
android:id="#+id/progress"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<LinearLayout
android:id="#+id/llSearch"
android:visibility="visible"
android:background="#50AAAAAA"
android:paddingTop="10dp"
android:gravity="center_vertical"
android:paddingBottom="10dp"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="72dp">
<ImageView
android:layout_marginLeft="16dp"
android:layout_marginStart="16dp"
android:src="#drawable/abc_ic_search_api_mtrl_alpha"
android:layout_width="40dp"
android:layout_height="40dp" />
<EditText
android:textColor="#android:color/white"
android:textColorHint="#android:color/white"
android:background="#android:color/transparent"
android:visibility="visible"
android:maxLines="1"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<android.support.v7.widget.RecyclerView
android:visibility="invisible"
android:layout_marginTop="72dp"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<android.support.v7.widget.RecyclerView
android:visibility="gone"
android:layout_marginTop="72dp"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<com.myapp.custom.RevealView
android:id="#+id/reveal"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</merge>
When running the app through DDMS, I've noticed that the layout ends up being measured twice, why is this and how can I prevent overdraw?
What's also strange is that I can't figure out where the other LinearLayouts are coming from.
Measuring twice isnt overdraw. Depending on the type of layout you're using Android might need to measure it twice because of the relationship between child views require it. This can happen with layouts like LinearLayout or RelativeLayout. For exact reason you need to check the source of those, but its hardly an issue (usually).
But if you have something like a recycleview you should avoid using big nested layouts inside.

Animating a view to be stacked on top of the view it is behind

In my Android app, I have a view behind another view in a FrameLayout. I'd like to animate the hidden view at times so that it appears above the view that's shown. Here's my XML:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="#+id/options_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="#color/light_gray"
android:gravity="right"
>
<Button
android:id="#+id/option_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingEnd="8dp"
android:paddingRight="8dp"
android:background="#color/transparent"
android:text="#string/option_button"
android:textColor="#color/white"/>
</LinearLayout>
<LinearLayout
android:id="#+id/commentContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/white"
android:elevation="5dp"
android:paddingLeft="16dp"
android:paddingStart="16dp">
<EditText
android:id="#+id/commentText"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="5"
android:maxLines="1"
android:inputType="textCapSentences"
/>
<ImageButton
android:id="#+id/commentSubmit"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#color/light_gray"
android:textAllCaps="true"
android:text="#string/submit_comment"
android:src="#drawable/ic_send_white_24dp"
android:textColor="#color/white"/>
</LinearLayout>
</FrameLayout>
</LinearLayout>
Ideally, when I start typing in commentText, options_container would animate up above commentContainer. It seems like when I try to animate options_container though, nothing really happens. Just to check, I tried:
view.animate().y(200);
And I didn't see a change. Is this because what I'm trying to do is stack a view on top of another (by way of animation) inside of a FrameLayout?
First, vishnus's comment is right that you need to call start() to make the animation work.
But even you do that, it won't work because the code is just moving the view along the y axis. What you really need is animate().z() which is added in API 21.

Button is behind the ListView in FrameLayout

I have a FrameLayout that consists of a list view and a button. The whole point of the FrameLayout is that elements that are after other elements will be displayed above them.
Since the button code is below the ListView code, I expected the button will always be on top, but it isn't. I can't figure it out - as soon as I get enough items in my list, the button is underneath it and it becomes obsolete.
XML:
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ListView
android:id="#+id/lvMovies"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:background="#fff"
android:elevation="3dp"
android:paddingTop="8dp" />
<Button
android:id="#+id/btnAddMovie"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_gravity="bottom|end"
android:layout_marginBottom="16dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:background="#drawable/raised_action_button"
android:elevation="5dp"
android:fontFamily="sans-serif-light"
android:gravity="center"
android:text="+"
android:textColor="#ffffff"
android:textSize="30sp" />
</FrameLayout>
From developer.android:
FrameLayout is designed to block out an area on the screen to display
a single item. Generally, FrameLayout should be used to hold a single
child view,
The current dimensions of the framelayout is the entire screen. If I was to use the entire screen for the above layout I would do something like the following:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="5"
android:orientation="horizontal">
<ListView
android:id="#+id/lvMovies"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:background="#fff"
android:elevation="3dp"
android:paddingTop="8dp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal">
<Button
android:id="#+id/btnAddMovie"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_gravity="bottom|end"
android:layout_marginBottom="16dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:background="#drawable/raised_action_button"
android:elevation="5dp"
android:fontFamily="sans-serif-light"
android:gravity="center"
android:text="+"
android:textColor="#ffffff"
android:textSize="30sp" />
</LinearLayout>
</LinearLayout>
You can say 0dp weight for either a height or a width, but not both. You then team it up with a layout_weight. In this case the first nested linear layout takes up 5/6ths of the screen, the second 1/6th. Thus your button sits in a protected space that the list view will not block out.
The outer linear layout has a vertical orientation which makes the two inner layouts stack on top of each other, the inners are horizontal to make them go across the entire screen. You will need to tweak those weights to make it work for you.
You can use RelativeLayout for this. If you want button view over the listview android:layout_above="#+id/btnAddMovie" delete this line.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ListView
android:id="#+id/lvMovies"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#+id/btnAddMovie"
android:layout_marginBottom="8dp"
android:background="#fff"
android:elevation="3dp"
android:paddingTop="8dp" />
<Button
android:id="#+id/btnAddMovie"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_alignParentBottom="true"
android:layout_gravity="bottom|end"
android:layout_marginBottom="16dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:elevation="5dp"
android:fontFamily="sans-serif-light"
android:gravity="center"
android:text="+"
android:textColor="#ffffff"
android:textSize="30sp" />
</RelativeLayout>
Remove the elevation property from the list view. That's it.
It seems like the elevation causes the element to be on top of other elements.

Categories

Resources