I have a weird problem that I'm having problems even articulating.
My layout is a relative layout that contains a scrollview that contains chips and an edit text. Below the scroll view, is a listview for auto completion, below which is a linear layout that houses an edit text and a button. (Screen shots at the end of this post).
When the fragment loads and the user types into the edittext inside the scroll view, the listview with auto complete options pops up. When an auto complete option is selected that is added as a selected chip. The library that generates those chips does not clear focus of the edit text, but something is jogging the OS to move focus to the bottom edit text. This results in the weird state that BOTH edit texts are blinking as if they had focus. If the user starts typing on the keyboard again the focus is actually on the the lower edit text, and it's now impossible to focus on the first edit text again to type.
The code for the NonFocusingScrollView is as follows. This properly fixed my issue where the scroll view around the ChipsView was grabbing focus and preventing the edit text from working correctly at all. (The SevenChipsView in the layout is merely an extension of ChipsView).
I've tried, programatically, removing focus from the lower edit text, and explicitly putting it back into the edit text in the scroll view, but that doesn't do anything.
Is there a way that I can prevent the OS from shifting focus around, and stay in the top edit text until the user taps the bottom edit text?
public class NonFocusingScrollView extends ScrollView {
public NonFocusingScrollView(Context context) {
super(context);
}
public NonFocusingScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NonFocusingScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public NonFocusingScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
#Override
protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
return true;
}
#Override
public ArrayList getFocusables(int direction) {
return new ArrayList();
}
#Override
public void requestChildFocus(View child, View focused) {
// avoid scrolling to focused element all together
}
}
Layout XML
<?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">
<LinearLayout
android:id="#+id/messaging_announcement_recipient_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:background="#color/screen_background"
android:orientation="horizontal"
android:padding="8dip">
<TextView
style="#style/default_textview"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginEnd="8dip"
android:layout_marginLeft="0dp"
android:layout_marginRight="8dip"
android:layout_marginStart="0dp"
android:gravity="center_vertical"
android:text="#string/recipient_to"
android:textColor="#android:color/white" />
<com.sevenshifts.android.views.NonFocusingScrollView
android:id="#+id/messaging_announcements_recipients_scroll_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:focusable="true"
android:focusableInTouchMode="true"
android:padding="0dp">
<com.sevenshifts.android.views.SevenChipsView
android:id="#+id/messaging_announcements_recipients"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="0dp"
android:textColor="#android:color/white"
app:cv_bg_color_clicked="#color/primary"
app:cv_color_clicked="#color/primary"
app:cv_icon_placeholder="#drawable/ic_house" />
</com.sevenshifts.android.views.NonFocusingScrollView>
</LinearLayout>
<se.emilsjolander.stickylistheaders.StickyListHeadersListView
android:id="#+id/messaging_announcements_recipient_autocomplete"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/messaging_announcement_recipient_container"
android:visibility="gone" />
<LinearLayout
android:id="#+id/messaging_announcements_compose_post_container"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginLeft="8dip"
android:layout_marginRight="8dip"
android:minHeight="44dip"
android:orientation="horizontal">
<EditText
android:id="#+id/messaging_announcement_post_text"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="#string/announcement_hint"
android:inputType="textMultiLine|textCapSentences|textAutoCorrect"
android:maxLines="5" />
<Button
android:id="#+id/messaging_announcement_post_button"
android:layout_width="80dp"
android:layout_height="44dip"
android:background="#null"
android:text="#string/send"
android:textColor="#color/primary" />
</LinearLayout>
<include layout="#layout/component_loading" />
</RelativeLayout>
Screen shot flow is in this imgur gallery - there's too many to not crowd this post: http://imgur.com/a/zWY0D
Related
I am trying to implement horizontal timeline. SO I have written the code to design the horizontal line but I am able to figure out how I will write text on the above and below of the line.
One more thing I don't want to use any other library.
I have try to solve it through Custom view as people here have been suggested but got struck.
timeline_segment.xml
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:weightSum="1"
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:padding="3dp"
android:textAlignment="textEnd"
android:text="Top"
android:id="#+id/top_data"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_gravity="center"
android:layout_weight="0.5"
android:background="#color/alphabet_a"
android:layout_width="wrap_content"
android:layout_height="2dp" />
<ImageView
android:background="#drawable/circle1"
android:layout_width="15dp"
android:layout_height="15dp" />
<TextView
android:layout_weight="0.5"
android:layout_gravity="center"
android:background="#color/alphabet_a"
android:layout_width="wrap_content"
android:layout_height="2dp" />
</LinearLayout>
<TextView
android:padding="3dp"
android:gravity="center"
android:text="bottom"
android:id="#+id/bottom_data"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</merge>
timeline_segment.java
public class timeline_segement extends LinearLayout {
View rootView;
TextView upperText;
TextView startLine;
TextView endLine;
ImageView circleView;
TextView bottomText;
public timeline_segement(Context context) {
super(context);
init(context);
}
public timeline_segement(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public timeline_segement(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
rootView=inflate(context, R.layout.timeline_segment, this );
upperText=(TextView) rootView.findViewById(R.id.top_data);
bottomText=(TextView) rootView.findViewById(R.id.bottom_data);
upperText.setText("Top");
bottomText.setText("Bottom");
}
public void setUpperText(String string)
{
upperText.setText(string);
}
public void setBottomText(String string)
{
bottomText.setText(string);
}
}
Decided to answer because the comment box is kinda limiting. This is my comment:
You'll need a custom view to achieve this. You can either composite ready-made views or go full custom
If you choose to composite views, then you start by breaking down that image level by level. At the highest level, its a horizontal layout with 'TimelineCell's (or whatever you choose to call it).
A TimelineCell will basically be a vertical LinearLayout with a right aligned TextView, a View that draws the line and another center aligned TextView.
You can then create these programmatically and add them to a parent horizontal LinearLayout.
If you however choose to go full custom, Youll have to handle measuring, layouting and drawing of all the components including the text above and below the line.
Take a look at this link for a good introduction to custom views on android
I am trying to achieve following structure (image below). As you can see there are two sections with RecyclerViews and CardViews in it. These two sections are divided by two TextViews with Buttons.
Each section should match screen width (minus indent between cards). Each CardView has square ImageView in it. So the height of CardView itself depend on screen width: card_height = screen_width - indent_between_cards + space_for_card_text. To achieve this behaviour I use simple SquareImageView, which looks like this:
public class SquaredImageView extends ImageView {
public SquaredImageView(Context context) {
super(context);
}
public SquaredImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SquaredImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();
setMeasuredDimension(width, width);
}
}
The CardView layout looks like this:
<CardView
android:id="#+id/card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="0dp"
android:background="#color/snow"
android:clickable="true"
android:orientation="vertical">
<!-- Image -->
<com.test.views.SquaredImageView
android:id="#+id/card_image"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- Content -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="32dp"
android:orientation="horizontal">
<!-- Title -->
<TextView
android:id="#+id/card_title"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_vertical"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:singleLine="true"
android:textColor="#color/stone_dark"
android:textSize="14sp" />
<!-- Button -->
<ImageView
android:id="#+id/card_menu"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:clickable="true"
android:scaleType="center"
android:src="#drawable/ic_menu" />
</LinearLayout>
</CardView>
It means, that RecyclerView's adapter don't know the dimensions of CardView in advance.
As you probably know, RecyclerView has no system, which can measure its child-views, to make wrap its content correctly.
But unpredictable SquareImageView + fullscreen RecyclerView works fine in most of cases except the one described in this question.
So what's the problem? You should use your own LayoutManager or WrappableLayoutManager by #se-solovyev to solve your problem.
The problem is in unpredictable SquareImageView. When LayoutManager tries to measure its child, it gets nothing. It means that RecyclerView displayed in fullscreen (as if height and width are set to match_parent).
So the question is: how to make RecyclerView with unpredictable SquareImageViews wrap its content correctly?
I am implementing a RecyclerView inside a ScrollView. In order to have only one scrolling behaviour on the entire page I implement a NonScrollRecyclerView version. The implementation is as follows:
public class NonScrollRecyclerView extends RecyclerView {
public NonScrollRecyclerView(Context context) { super(context); }
public NonScrollRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NonScrollRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public boolean dispatchTouchEvent(MotionEvent ev){
if(ev.getAction() == MotionEvent.ACTION_MOVE)
return true;
return super.dispatchTouchEvent(ev);
}
}
Once i update my build and target settings to SDK 23, I have trouble scrolling the page which contains the NonScrollRecyclerView. The specific problem is that the page scrolls OK until i reach the recycler view portion and once i scroll onto this view I am unable to scroll anymore, either up or down.
I DONOT face this problem with SDK 22 and below
My xml is as follows:
XML #layout/rv contains the recycler view
<ScrollView 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:background="#color/background_gray">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/background_gray"
android:orientation="vertical">
<include
layout="#layout/row_mall_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/cv_mall_header"
android:layout_marginTop="8dp"/>
<include
layout="#layout/row_mall_shops"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/cv_mall_shops"
android:layout_marginTop="8dp"/>
<include
layout="#layout/row_mall_coupons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/cv_mall_coupons"
android:layout_marginTop="8dp"/>
<include
layout="#layout/rv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/cv_mall_feeds"
android:layout_marginTop="8dp"/>
</LinearLayout>
</ScrollView>
XML - #layout/rv
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/background_gray"
android:id="#+id/ll_mall_feeds">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/white"
android:paddingTop="6dp"
android:paddingBottom="6dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/tv_feedcount"
android:textColor="#color/semi_theme_blue"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginLeft="12dp"
android:layout_centerVertical="true" />
</RelativeLayout>
<com.project.ui.NonScrollRecyclerView
android:id="#+id/nrv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="#android:color/transparent"
android:listSelector="#android:color/transparent" />
</LinearLayout>
RecyclerView and ListView are not recommended inside a ScrollView because elements hights are not calculated when rendering the ScrollView. This means, your adapter might not be populated when the ScrollView is shown and later when the RecyclerView is notified about data changes (for instance when you initialize your adapter), there's not way to recalculate the elements heights.
It's really a pain in the neck because you have to try to calculate the elements heights and it's never accurate, so you will have discrepancies when showing a ListView or a RecyclerView inside a ScrollView. Some examples of how to calculate the elements heights can be checked here and here.
My advice is to turn your RecyclerView into a LinearLayout and add elements programmatically, so you emulates the ListView or RecyclerView behaviour:
LinearLayout layout = (LinearLayout) rootView.findViewById(R.id.files);
layout.removeAllViews();
for (int i = 0; i < fileAdapter.getCount(); i++) {
final View item = fileAdapter.getView(i, null, null);
item.setClickable(true);
item.setId(i);
item.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
fileContentRowPosition = v.getId();
# Your click action here
}
});
layout.addView(item);
}
Here its the XML with the files definition:
<ScrollView
android:id="#+id/scrollView1"
android:layout_width="match_parent"
android:layout_height="match_parent">
...
<LinearLayout
android:id="#+id/files"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:orientation="vertical">
</LinearLayout>
</ScrollView>
The whole java code can be checked here and the whole Layout here.
On the other hand, if you still want to continue with your implementation, and regarding your issue, you can check this article about Handling Scrollable Controls in Scrollview
Best regards,
For only one scrolling in the entire page you can use NestedScrollView instead of ScrollView and set recyclerView.setNestedScrollingEnabled(false);
I want to create a LinearLayout with two TextViews: a label and a data placeholder. Since the data can be arbitrarily long, I want to restrict the size of the second TextView to a single line, and to automatically scroll horizontally if the data does not fit in the view.
Also, I want the width of the second TextView to be calculated at runtime, so that it can fill 70% of the parent container and be aligned to its right.
So far this is what I've got:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:id="#+id/ll_denunciante" >
<TextView
android:id="#+id/txtv_label_denunciante"
android:layout_width="0px"
android:layout_height="wrap_content"
android:layout_weight="0.3"
android:gravity="left"
android:text="#string/txtv_label_denunciante" />
<TextView
android:id="#+id/txtv_data_denunciante"
android:layout_width="0px"
android:layout_height="wrap_content"
android:layout_weight="0.7"
android:gravity="right"
android:maxLines="1"
android:ellipsize="marquee"
android:scrollHorizontally="true"
android:marqueeRepeatLimit="marquee_forever"
android:text="#string/txtv_no_data" />
</LinearLayout>
But the text is simply cut off. It is not ellipsized and automatic scrolling does not work.
Adding
android:focusable="true"
android:focusableInTouchMode="true"
does not fix the problem.
The answer to this question did not help either.
I'll gladly accept an answer using a RelativeLayout if it accomplishes the desired result using less code or if it is not possible using a LinearLayout.
Edit
Changing the second TextView to:
<TextView
android:id="#+id/txtv_data_denunciante"
android:layout_width="0px"
android:layout_height="wrap_content"
android:layout_weight="0.7"
android:ellipsize="marquee"
android:gravity="right"
android:marqueeRepeatLimit="marquee_forever"
android:singleLine="true"
android:text="#string/txtv_no_data" />
and adding
txtvDataDenunciante.setSelected(true);
fixed it.
I tried this way and it works. Replace your 2nd TextView with the one below. Here is the Result in the attached screenshot.
<TextView
android:id="#+id/txtv_data_denunciante"
android:layout_width="0px"
android:layout_height="wrap_content"
android:layout_weight="0.7"
android:ellipsize="marquee"
android:gravity="right"
android:focusable="true"
android:focusableInTouchMode="true"
android:scrollHorizontally="true"
android:marqueeRepeatLimit="marquee_forever"
android:maxLines="1"
android:singleLine="true"
android:freezesText="true"
android:text="#string/txtv_no_data"
android:selectAllOnFocus="true" />
EDIT : If XML attributes don't work in your case, then the problem is about taking the focus. In some cases, parent Layouts or some others take the focus on theirself. So you need to gain the focus for the particular View element yourself on the RunTime. To do that, you can set your TextView as selected.
yourTextView.setSelected(true);
If it is in a ListView, the problem is that you TextView does not get the focus.
Change your TextView to use this one :
public class AutoScrollingTextView extends TextView {
public AutoScrollingTextView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
public AutoScrollingTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AutoScrollingTextView(Context context) {
super(context);
}
#Override
protected void onFocusChanged(boolean focused, int direction,
Rect previouslyFocusedRect) {
if (focused) {
super.onFocusChanged(focused, direction, previouslyFocusedRect);
}
}
#Override
public void onWindowFocusChanged(boolean focused) {
if (focused) {
super.onWindowFocusChanged(focused);
}
}
#Override
public boolean isFocused() {
return true;
}
}
With these parameters :
android:scrollHorizontally="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
As seen here : https://stackoverflow.com/a/9707140/1318795
I am working on an android application that will get data from an xml file and insert it in a listview
but I want to change the UI and instead of displaying the data in a listview vertically, I want to display them horizontally in a scrollview
My question is if I have the following code
<HorizontalScrollView
android:id="#+id/horizontalScrollView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scrollbars="none">
<LinearLayout
android:id="#+id/linearLayout1"
android:orientation="horizontal"
android:layout_height="wrap_content"
android:layout_width="wrap_content" android:padding="2dp">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView
android:layout_width="wrap_content"
android:id="#+id/imageView11"
android:layout_height="wrap_content"
android:src="#drawable/i1"/>
<TextView
android:id="#+id/TextOnImage11"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Fantasia Reviews"
android:layout_alignParentBottom="true"
android:paddingLeft="2dp"
android:background="#drawable/txt_bg"
android:textSize="10dp"
android:paddingTop="2dp"
android:textColor="#FFFFFF"
android:textStyle="bold"
android:width="0dp" />
</RelativeLayout>
</LinearLayout>
</HorizontalScrollView>
how can I add more images and text dynamically from the java code ??
Thank you
I presume that your intent would be to add another RelativeLayout with it's own image/text pair straight after the RelativeLayout that you have shown in your code sample?
In that case as it is not simply adding one more view, I would take the time to create a class that represents your "structure" that you want to insert.
e.g. A class called "TextImagePair" that extends "RelativeLayout"
public class TextImagePair extends RelativeLayout {
public ReportDetailRow(Context context){
super(context);
}
public TextImagePair(Context context,AttributeSet attributeSet){
super(context, attributeSet);
}
public TextImagePair(Context context,AttributeSet attributeSet, int i){
super(context, attributeSet,i);
}
public TextImagePair(Context context, AttributeSet attributeSet, String text, int drawableResource) {
super(context, attributeSet);
// Inflate the layout
LayoutInflater inflator = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflator.inflate(R.layout.lay_textimagepair, this);
TextView tvText = (TextView)this.findViewById(R.id.layTextImagePair_textview);
tvText.setText(text);
ImageView imgView = (ImageView)this.findViewById(R.id.layTextImagePair_imageview);
imgView.setDrawable(getResources().getDrawable(drawableResource));
}
}
You would then have a seperate xml layout file (named lay_textimagepair in my code) that just contains the text and image views.
You would then add this to your view at run time with:
LinearLayout parent = (LinearLayout)findViewById(R.id.layParentView_liniearlayout);
TextImagePair tip = new TextImagePair(null,null,"Blah Blah Blah",R.drawable.something);
parent.addView(tip);
Sorry if there are any bugs in the above code but I am writing it without access to Eclipse!