I have LinearLayout and inside 2 TextView both have marquee and when I update text in first then second TextView restarts marquee.
<LinearLayout
android:id="#+id/panel"
android:layout_width="320dp"
android:layout_height="match_parent"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:gravity="center_vertical"
android:orientation="vertical" >
<TextView
android:id="#+id/first"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:gravity="bottom|center_horizontal"
android:marqueeRepeatLimit="marquee_forever"
android:singleLine="true" />
<TextView
android:id="#+id/second"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:gravity="top|center_horizontal"
android:marqueeRepeatLimit="marquee_forever"
android:singleLine="true"
/>
</LinearLayout>
I found that if for R.id.first and R.id.second i set layout_width="320dp" the effect don't occurs.
But I want to set android:layout_width="match_parent" there is some workaround?
I found similar problem but without solution:
Android, RelativeLayout restarts Marquee-TextView when changing ImageView in same RelativeLayout
I had a similar problem and the solution IS to set fixed size for the Textview.
So why not do it progammatically? In my case, it solved the problem. Here is my solution in details :
The layout is a bit complex with a lot of changing values. Here is the interesting part :
layout.xml :
<!-- The height and visibility values change programatically -->
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="30dp"
android:layout_alignParentBottom="true"
android:visibility="gone" >
<FrameLayout>
...
// some code
...
</FrameLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal" >
<TextView
android:layout_width="wrap_content"
android:layout_height="fill_parent" />
<!-- My scrolling textview. see below. -->
<!-- The size will be set when -->
<!-- the layout will be draw, -->
<!-- after the Activity.onCreate(). -->
<!-- I removed ALL THE UNECESSARY (I mean -->
<!-- scrollHorizontally, focusable and focusableInTouchMode. -->
<!-- You don't need it !!!!) -->
<fr.cmoatoto.android.widget.ScrollingTextView
android:id="#+id/text"
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever" />
<ImageView
...
// some code
... />
</LinearLayout>
</RelativeLayout>
The ScrollingTextView has been defined in this answer
Here it is again :
ScrollingTextView.java :
public class ScrollingTextView extends TextView {
public ScrollingTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public ScrollingTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ScrollingTextView(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;
}
}
And finally the Activity. As I said before, You need to set fixed width and height so we will do it programmatically with a listener in the onCreate() :
MyActivity.java :
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout);
TextView textView = ((TextView) findViewById(R.id.home_trafic_text));
textView.setText(getString(R.string.loading));
textView.setEnabled(true); // Thanks to Romain Guy
textView.addOnLayoutChangeListener(new OnLayoutChangeListener() {
#Override
public void onLayoutChange(View v, int left, int top, int right,
int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
LayoutParams params = v.getLayoutParams();
params.width = right - left;
params.height = bottom - top;
params.weight = 0;
v.removeOnLayoutChangeListener(this);
v.setLayoutParams(params);
}
});
}
Be careful if you need to change orientation or things like that but it works pretty well for me !
----EDIT FOR PRE-API-11---
Because OnLayoutChangeListener exists only from Api v11, there is a workaround (It works but I think it is less good) :
Remove the OnLayoutChangeListener from your activity :
MyActivity.java :
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout);
TextView textView = ((TextView) findViewById(R.id.home_trafic_text));
textView.setText(getString(R.string.loading));
textView.setEnabled(true); // Thanks to Romain Guy
}
and add a onSizeChanged in your ScrollingTextView :
ScrollingTextView.java :
public class ScrollingTextView extends TextView {
...
// Same code as before
...
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
LayoutParams params = (LayoutParams) getLayoutParams();
params.width = w;
params.height = h;
params.weight = 0;
setLayoutParams(params);
}
}
I hope it helps !
You should prevent putting both marquee in the same ViewGroup. In your case, you can wrap each marquee TextView with a LinearLayout (this won't work if using RelativeLayout).
just a simple Fix..:) no need to worry much...just fix width of textview as some 800dp or too higher width. it will solve reset issue
Related
I build customView extending LinearLayout and having simple 3 childrens(2 TextView and ImageView). I create this view dynamically in code and adding it to parent LinearLayout. This view has background, so I can easily spot on the screen, that it is inflated correctly in its place, but any of child is not visible. I checked LayoutInspector and it shows that everything is setted correctly(text values to TextViews and picture to ImageView), but somehow when I try to locate them on inspector they are shown as little dot over my customView:
My CustomView is called DayTileView and this is square with gray background. As you can see on inspector on the left childrens are filled with content. Layout of View:
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<merge>
<TextView
android:id="#+id/day"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:textColor="#android:color/white"
/>
<TextView
android:id="#+id/dayName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:textColor="#android:color/white"
/>
<ImageView
android:id="#+id/padlock"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:src="#drawable/ic_padlock"
/>
</merge>
</layout>
And its code:
public class DayTileView extends LinearLayout {
private DayTileBinding mBinding;
public DayTileView(Context context) {
super(context);
init();
}
public DayTileView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public DayTileView(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mBinding = DataBindingUtil.inflate(LayoutInflater.from(getContext()), R.layout.day_tile, this, true);
setOrientation(VERTICAL);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
setMeasuredDimension(width, width);
}
public void setDay(int day, int month, int year) {
DateTime settedDay = new DateTime().withYear(year).withMonthOfYear(month).withDayOfMonth(day);
mBinding.day.setText(String.valueOf(day));
String dayName = settedDay.dayOfWeek().getAsText();
mBinding.dayName.setText(dayName);
boolean isWeekend = settedDay.dayOfWeek().get() == 6 || settedDay.dayOfWeek().get() == 7;
setBackgroundColor(ContextCompat.getColor(getContext(), isWeekend ? R.color.weekend_bg : R.color.weekday_bg));
}
}
Its use in another CustomView which is also LinearLayout but wiht horizontal orientation (PlannedDayView on inspector):
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<merge>
<*.customViews.DayTileView
android:id="#+id/dayTile"
android:layout_width="0dp"
android:layout_weight="0.2"
android:layout_height="wrap_content"/>
<LinearLayout
android:id="#+id/container"
android:orientation="vertical"
android:layout_weight="1.2"
android:layout_width="0dp"
android:layout_height="wrap_content"/>
</merge>
</layout>
Has anyone any idea what could be casuing this (childs out of view)? When I replace merge for LinearLayout with vertical orientation and same background everything in Design mode of layout is visible correctly, so it should work.
EDIT:
I found out, that if I set during View initalization Padding Top to 10px then dot is moving down. So it looks like from some reasons Android didn't made to inflate correctly TextViews and ImageView
I found out what was the problem:
I overrided onMeasure and didn't measure child Views. Earlier I was using such code to make square View not square ViewGroup.
Corrected code:
final int width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
setMeasuredDimension(width, width);
super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY));
After setting correct width and height for View I must measure whole view with new MeasureSpec
My problem is, when i turn on a setting in the developer options to see view bounds, i can see that the orange "20" text wraps much larger space than it is requried. (top and bottom)
I tried to set: android:includeFontPadding="false" but it is just simple push up the content, leaving a big empty space bottom of the text's container.
How can i remove the extra space?
XML:
<LinearLayout
android:id="#+id/topDash"
android:layout_width="180dp"
android:layout_height="180dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:background="#drawable/circle_gray"
android:orientation="vertical" >
<TextView
android:id="#+id/RobotoTextView02"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="#string/sog_C"
android:textColor="#color/blue_medium"
android:textSize="20sp" />
<TextView
android:id="#+id/RobotoTextView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="20"
android:textColor="#color/orange"
android:textSize="100sp" />
<TextView
android:id="#+id/robotoTextView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="KM/H"
android:textColor="#color/gray_darker"
android:textSize="24sp" />
</LinearLayout>
Very nice question. I'm not sure that it possible to do it only in XML and without setting any hard coded value for scrollY property, but I implemented a small custom class without hard coded values, which you can use without any modifications in other places. In such situations onMeasure method always come to help :) I use default font here. If you use different typeface, call textPaint.setTypeface() and set it before textPaint.getTextBounds statement.
public class CustomTextView extends TextView {
private int newWidth;
private int newHeight;
public CustomTextView(Context context) {
super(context);
}
public CustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if(newHeight == 0) {
Rect textBounds = new Rect();
Paint textPaint = new Paint();
textPaint.setTextSize(getTextSize());
textPaint.getTextBounds(getText().toString(), 0, getText().length(), textBounds);
int descent = (int) textPaint.descent();
newWidth = textBounds.width();
newHeight = textBounds.height() - 2 * descent;
setScrollY(descent);
}
setMeasuredDimension(newWidth, newHeight);
}
}
But this solution is only good for numbers, why only for numbers, because of descent, and that's why we cant remove that extra space ony inside the XML, it is a font property
I have made a Custom ViewGroup. Detail about this Custom ViewGroup is found here from my earlier question. The problem I am facing here is , whenever I try to add buttons in the LinearLayout that is inside the custom Viewgroup, the buttons never get shown. I have tried many things but the button is never displayed, do I have to do something in the custom viewgroup, I even tried inflating the button but still did not work.
Code for Custom ViewGroup:
public class RootViewLayout extends ViewGroup {
private View mDrawView;
private View mSlideView;
private int mTop;
private int mDragRange;
public RootViewLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onFinishInflate() {
mDrawView = findViewById(R.id.content_frame_white);
mSlideView = findViewById(R.id.slide_frame);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(widthSize, heightSize);
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom){
bringChildToFront(mDrawView);
mDrawView.layout(0, 0, right, bottom);
mSlideView.layout(0, 0, right/2, bottom);
}
}
and the XML :
<com.example.drawapp.RootViewLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/Root_View_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white">
<com.example.drawapp.DrawView
android:id="#+id/content_frame_white"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/whitepaperwithcoffeestain">
</com.example.drawapp.DrawView>
<LinearLayout
android:id="#+id/slide_frame"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="#drawable/slidebackgrd"
android:orientation="vertical">
<Button
android:id="#+id/pen"
android:layout_width="100dip"
android:layout_height="wrap_content"
android:background="#drawable/pic"/>
</LinearLayout>
</com.example.drawapp.RootViewLayout>
sorry for the late comment.if you didn't solve it yet,apparently you have to do the same to your button what you did for your LinearLayout
View b= mSlideView.findViewById(R.id.pen);
b.layout(0, 0, right/4, bottom);
checked it and it displayed the buttons width as half of the linearlayout and height as the bottom parameter
I have been created a button and use addView() to draw some chart in onClickListener(). But it will not extend the height of view automatically if the chart out of bound.So I want to add the height of view when all chart have been drawn. I try to use getLayoutParams().height to modify the height but it doesn't work.
public class MainActivity extends Activity {
private TableLayout layout;
private Button btnDraw;
public void onCreate(Bundle savedInstanceState){
layout=findViewById((TableLayout) findViewById(R.id.tableLayout));
btnDraw=findViewById((Button) findViewById(R.id.btnDraw));
btnDraw.setOnClickListener(new OnClickListener(){
public void onClick(View arg0) {
layout.addView(new Chart(MainActivity.this)
}
});
}
class Chart extends View {
public void onDraw(Canvas c) {
int addHeight=0;
for(...){ //draw several chart
...
addHeight+=500;
}
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) layout.getLayoutParams();
params.height += addHeight;
layout.setLayoutParams(params);
}
}
}
here is xml code
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
<TableLayout
android:id="#+id/tableLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:stretchColumns="1">
<TableRow>
<Button
android:id="#+id/btnDraw"
android:layout_span="2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Draw" />
</TableRow>
...
</TableLayout>
</ScrollView>
I also try to call onMeasure(getWidth(),addHeight) outside the for loop but it still not work.
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(widthMeasureSpec, widthMeasureSpec);
}
Your Chart class should implement onMeasure() if you want to do it the eight way. If it is just a hack you can use AbsoluteLayout. You can also play with setting the layout params, but you should call updateViewLayout() and possibly even requestLayout().
In default handle button in android SlidingDrawer in the centre of the drawer. Is it possible to change that position to left or right..? If it possible how can I do that, android:gravity="left" is not work in the button.
Put your handle in a RelativeLayout, and set android:layout_alignParentRight="true" on the handle.
For example like this:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/hello" />
<SlidingDrawer android:id="#+id/drawer"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:handle="#+id/handle"
android:content="#+id/content">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/handle">
<ImageView android:src="#drawable/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true" />
</RelativeLayout>
<LinearLayout
android:gravity="center"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#aaaa00" android:id="#+id/content">
<ImageView android:src="#drawable/icon"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center">
</ImageView>
</LinearLayout>
</SlidingDrawer>
</FrameLayout>
The problem I had with HenrikS answer was that in my case I had some views behind the relative layout and when I tried to click them I realized that the relative layout was intercepting those clicks because the width was set to fill_parent.
To workaround this I modified the layout of the handler view (the ImageView) in my case to the left, hope it is helpful.
public class CustomSlidingDrawer extends SlidingDrawer {
public CustomSlidingDrawer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CustomSlidingDrawer(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
final int height = b - t;
ImageView handle = (ImageView) getHandle();
int childLeft = 0;
int childWidth = handle.getWidth();
int topOffset = 0;
int bottomOffest = 0;
int childHeight = handle.getHeight();
int childTop = this.isOpened()?topOffset:height - childHeight + bottomOffest;
handle.layout(childLeft, childTop , childLeft + childWidth, childTop+childHeight);
}
}
The idea is simple: set the handle's padding to the correct value depending on the alignment you want.
In the example below, I derive a class from SlidingDrawer and override onLayout as follows. My sliding drawer is at the bottom of the screen, and I want the handle to be left-aligned rather than center-aligned.
public class ToolDrawer extends SlidingDrawer {
private int m_handleWidth = 0; // original handle width
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
if (x <= m_handleWidth) {
return super.onTouchEvent(event);
}
return false;
}
protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (changed) {
ImageView iv = (ImageView) getHandle();
iv.setPadding(0, 0, getWidth() - iv.getWidth(), 0);
if (m_handleWidth == 0) {
m_handleWidth = iv.getWidth();
}
}
}
}
It's as simple as that.
I tried android:paddingBottom="300dp" for the ImageView and it works fine, also with left, right and top.
But you have to set the padding from the middle-position, so bottom="300dp" means the handle move up 300 from the middle
A simpler solution for left-aligned handle:
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
final View handle = getHandle();
handle.layout(0, handle.getTop(), handle.getWidth(), handle.getBottom());
}
I have researched this problem for 2 days and I realized that you need to use another library. Because, when you use RelativeLayout or LinearLayout, you're just get fill_parent screen and of course it will be affected by touching ( although you don't touch on icon ).
So, I use SlidingTray from Sileria library ( ver 3.5 ) http://aniqroid.sileria.com/doc/api/
Then like this
I found the solution for garibay
You just need to set android:clickable="true" on content layout of sliding drawer.