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
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 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
How come the following code not working. I have something similar at other part of the layout and it works. But this part does not work. Any idea?
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:paddingLeft="50dip"
android:paddingRight="50dip"
android:focusable="true"
android:focusableInTouchMode="true"
android:layout_gravity="center_vertical"
android:id="#+id/statusTvBottom"
android:text="Status: "
android:layout_marginLeft="5dp">
</TextView>
</LinearLayout>
First, the text has to be longer than the "box" in order to marquee, if it fits-no marquee. I use this code:
<TextView
android:id="#+id/availability"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:focusable="false"
android:focusableInTouchMode="false"
android:gravity="center_vertical|center_horizontal"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:singleLine="true"
android:textColor="#343434"
android:textSize="#dimen/text_size_medium"
android:textStyle="bold|italic" />
Setting android:focusable="false" and android:focusableInTouchMode="false" allows it to marquee without focus.
First, you can try this:
textview.setSelected(true);
But it might not work when the text view can't get the focus all the time. So, to ensure TextView Marquee working, I had to use a custom TextView.
public class CustomTextView extends TextView {
public CustomTextView(Context context) {
super(context);
}
public CustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#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;
}
}
And then, you can use the custom TextView as the scrolling text view in your layout .xml file like this:
<com.example.myapplication.CustomTextView
android:id="#+id/tvScrollingMessage"
android:text="#string/scrolling_message_main_wish_list"
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit ="marquee_forever"
android:focusable="true"
android:focusableInTouchMode="true"
android:scrollHorizontally="true"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="#color/black"
android:gravity="center"
android:textColor="#color/white"
android:textSize="15dp"
android:freezesText="true"/>
NOTE: in the above code snippet com.example.myapplication is an example package name and should be replaced by your own package name.
Hope this will help you. Cheers!
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!
I am trying to implement a single-line text view that will scroll automatically. But I unfortunatly cannot get it to work. The AutoScrollTextView is declared inside a LinearLayout (width and height = fill_parent). The class basically uses a Handler that calls itself to scroll by a given amount. I have simplified the code to only show a text view that should be scrolling by 5 pixels every second.
The log output is correct, the getScrollX() method returns the appropriate scrollX position.
If I don't call requestLayout(), nothing gets drawn. invalidate() has no effect.
Would anybody have a clue?
public class AutoScrollTextView extends TextView {
public AutoScrollTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setSingleLine();
setEllipsize(null);
setText("Single-line text view that scrolls automatically if the text is too long to fit in the widget");
}
// begin to scroll the text from the original position
public void startScrolling() {
scrollHandler.sendEmptyMessage(0);
}
private Handler scrollHandler = new Handler() {
private static final int REFRESH_INTERVAL = 1000;
public void handleMessage(Message msg) {
scrollBy(5, 0);
requestLayout();
Log.debug("Scrolled to " + getScrollX() + " px");
sendEmptyMessageDelayed(0, REFRESH_INTERVAL);
}
};
}
If you don't need to sub-class the TextView, you can try this in your layout file:
<TextView
android:text="Single-line text view that scrolls automatically if the text is too long to fit in the widget"
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit ="marquee_forever"
android:focusable="true"
android:focusableInTouchMode="true"
android:scrollHorizontally="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
Also, in your code use the following:
findViewById(R.id.serviceColorCode).setSelected(true);
[Answer edited based on comments]
After these xml code as answered by #rajat
<TextView
android:text="Single-line text view that scrolls automatically if the text is too long to fit in the widget"
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit ="marquee_forever"
android:focusable="true"
android:focusableInTouchMode="true"
android:scrollHorizontally="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
We need to set
TextView tv=(TextView)findViewById(R.id.textview1);
tv.setSelected(true);
which finally made mine work
My solution works:
<TextView
android:id="#+id/titolotxt"
android:layout_width="..."
android:layout_height="..."
android:ellipsize="marquee"
android:gravity="left"
android:marqueeRepeatLimit="marquee_forever"
android:singleLine="true"
android:text="#string/titolo"/>
And the TextView have to be setted selected:
textView.setSelected(true); by code in onCreate for example.
// this TextView will marquee because it is selected
TextView marqueeText1 = (TextView) findViewById(R.id.marquee_text_1);
marqueeText1.setSelected(true);
<TextView
android:id="#+id/marquee_text_1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit."
android:textSize="24sp"
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true" />
Hint: Your Text should be big in length otherwise it won't work for small-length text if it does not exceed your screen size.
< TextView
android:id="#+id/support"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text=" enter the large text that wont fit on screen "
android:singleLine="true"
android:scrollHorizontally="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
/>
and in your activity
TextView textView=findViewById(R.id.support);
textView.setSelected(true);
In order to move text, besides adding attributes:
android:ellipsize="marquee"
android:singleLine="true"
android:marqueeRepeatLimit="marquee_forever"
android:focusable="true"
android:clickable="true"
android:focusableInTouchMode="true"
android:scrollHorizontally="true"
it is necessary for View to be in focus, so this can be done in two ways:
Programmatically:
tv.setSelected (true);
Do everything in XML by adding requestFocus tag:
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:singleLine="true"
android:marqueeRepeatLimit="marquee_forever"
android:focusable="true"
android:clickable="true"
android:focusableInTouchMode="true"
android:scrollHorizontally="true">
<requestFocus />
</TextView>
The only thing that worked for my case was using scrollview and setting the scroll programatically
Text View inside fragment
<HorizontalScrollView
android:id="#+id/hsv_fragment_drafting_now_header_info"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="8dp"
android:scrollbars="none">
<TextView
android:id="#+id/tv_fragment_drafting_now_header_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="#font/circular_std_book"
android:maxLines="1"
android:text="A very long text that will be reaching out the screen or view container"
android:textSize="16sp" />
</HorizontalScrollView>
Animation, sliding_text.xml
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="8000"
android:fromXDelta="100%"
android:interpolator="#android:anim/linear_interpolator"
android:repeatCount="infinite"
android:repeatMode="restart"
android:toXDelta="-100%" />
Block manual scroll and start animation
headerInfoScroll.setOnTouchListener(object : View.OnTouchListener{
override fun onTouch(p0: View?, p1: MotionEvent?): Boolean {
return true
}
})
headerInfo.startAnimation(AnimationUtils.loadAnimation(this.context, R.anim.sliding_text))
Sometimes invalidate wont work until you call invalidate in main thread like follows:
handler.post(new Runnable() {
#Override
public void run() {
yourView.invalidate();
}
});
setMovementMethod(new ScrollingMovementMethod()) with setHorizontallyScrolling(true) work in my case.
in .java:
tv = findViewById(R.id.textViewID);
tv.setMovementMethod(new ScrollingMovementMethod());
tv.setHorizontallyScrolling(true);