fake a View to portrait inside landscape-mode - android

I have an Activity in Landscape-Mode. Inside there is a Custom-Title-View aligned like this:
Is it possible to keep the landscape mode and 'fake' this one View into portrait-mode like this:
I have tried to overwrite my custom TitleView and put something like this to draw(Canvas)
public class VerticalTitle extends Title{
public draw(Canvas){
canvas.save();
canvas.rotate(getWidth() / 2, getHeight() / 2);
// i tryed many translations, but get none to work
canvas.translate(0, getHeight());
super.draw(canvas);
canvas.restore()
}
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
super.onMeasure(heightMeasureSpec, widthMeasureSpec);
setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
}
}
If it is on any interest, The TitleBar extends from RelativeLayout and has fixed height and fill_parent width
The setRotate parameter from View is not an option, because the app should stay compatible to 2.2.

you have to extend Text view And build your custom vertical TextView first see these two links for more details
Vertical TextView
Vertical rotated label
and after that in your Layout-land you can use this Xml file for your layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<com.yourpackage.CustomVerticalTextView
android:layout_width="42dp"
android:layout_height="fill_parent"
android:text="#string/hello"
android:background="#0000FF" />
</LinearLayout>
If you want to rotate the layout instead of rotating all of its children by 90 degrees use
LayoutAnimationController
see this SO thread for more details

I have never done this but I found two other answers here on SO that show ways you might accomplish this.
The first one involves extending the TextView class, and is here. Since you want to do a whole view though, I think the next answer is better suited to your situation.
The other answer is to create an animation using rotation to deal with it. That answer is here.

Related

Android: clipChildren=false and onClickListner for clipped children

I have a problem.
We have layout custom frame layout with scaling and translating functionality
public class MyFrameLayout extends FrameLayout {
...
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
getChildAt(0).setTranslationX(vTranslate.x);
getChildAt(0).setTranslationY(vTranslate.y);
getChildAt(0).setScaleX(mScale.scaleFactor);
getChildAt(0).setScaleY(mScale.scaleFactor);
}
The class listens for touch gestures and translations/scale its child.
I use it as parent viewgroup for my ViewGroup with content.
<MyFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/gray"
android:clipChildren="false">
<android.support.constraint.ConstraintLayout
android:id="#+id/calc_constraint_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clipChildren="false"/>
Content for constraint layout adds programmaticaly and it is bigger then screen or parent group. Because of it we set clipChildren=false.
But the children which was out of bounds before transation don't response on onClick events.
Some pictures:
Start screen
After translation:
The 6% node just doesn't answer to clicks.
Please, help me.
Add:
Well. I couldn't find the way to make constraint layout(white one) to fit the content with wrap_content value. My workaround was to dynamicaly increase width and height of the constraint layout accordingly width and height of my node tree.
When you add additional node - layout measures grows and you see how it tweaks abit. Then to fix it i had to override onLayout() method in parent layout (It's green on the screenshots, but it was custom ZoomableLayout).
And now everything works fine. But i'm not sure if this implementation ugly or not.

Difference in RelativeLayout and other in onMeasure

So, basically i have a custom view :
public class CustomView extends PercentFrameLayout
As you can see i've inherited it from PercentFrameLayout(might be the reason for this issue, but i'm not sure)
Inside of this view i've inflated layout .xml file:
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center">
<View
style="#style/SomeStyle"
app:layout_widthPercent="98%"
app:layout_heightPercent="98%"/>
....
</merge>
Also, in this custom view, i've overriden onMeasure method to multiply it's size by 2(just for test):
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(MeasureSpec.getSize(widthMeasureSpec) * 2|MeasureSpec.EXACTLY, MeasureSpec.getSize(heightMeasureSpec) * 2|MeasureSpec.EXACTLY);
}
Currently this custom view is in RelativeLayout:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center">
<com.example.CustomView
android:id="#+id/progress_new_collagen"
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_centerHorizontal="true"/>
</RelativeLayout>
The issue: Currently, its size not multiplied by two, its multiplied by, like 4 for width and 3 for height, and i don't know why.
The strange thing which made me want to ask a question: If it's not RelativeLayout as parent to this view, but any other ViewGroup class, like FrameLayout, LinearLayout and so on - code is working. It's also working if i just remove onMeasure. Is there any difference in this ViewGroups in case of onMeasure ?
RelativeLayout will call onMeasure() twice each time it is rendered. I think that this is why you are getting your strange results. If the second onMeasure() uses the results from the first call, that you will not double, but quadruple your dimensions.

TextView with ImageSpans inside RecyclerView = wrong layout

I'm inserting ImageSpans inside TextViews, which are part of a RecyclerView. Most of the time it works fine, but as you scroll up and down sometimes the TextView height is wrong for no obvious reason - there's too much vertical whitespace.
In this layout on a specific device, the correct height for a TextView with 1 line of text is 48, and the wrong height is 80 (I got these values from HierarchyViewer). The interesting thing is that the correct height for a TextView with 1 line of text including an ImageSpan is 80. So what seems to be happening is as the TextView gets recycled by RecyclerView, it sometimes keeps the height representing its old content (which included an ImageSpan).
This screenshot shows the "Anore" and "Halal blahs" TextViews as being 80 pixels high, which is wrong. The "Hello" TextView is correct at 48 pixels.
While investigating this I opened DDMS and ran "Dump UI hierarchy" and something interesting happened: the TextView heights corrected themselves on the fly:
That's pretty compelling evidence that the problem is TextView isn't being laid out properly after updating the text, so I tried various ways of calling forceLayout() and invalidate() on the TextView and its parent views, but it didn't help.
I tried replacing RecyclerView with ListView, no luck. I tried having all ImageSpans use the same drawable, no luck.
I ran HierarchyViewer but it didn't "fix" the layouts like UI Automator did. Not even when I pressed the "invalidate layout" and "request layout" buttons.
I'm not doing anything fancy to set the ImageSpans:
SpannableStringBuilder stringBuilder = new SpannableStringBuilder( rawText );
for( int i = inlineImages.size() - 1; i >= 0; i-- ) {
InlineImage img = inlineImages.get( i );
stringBuilder.insert( img.idx, "x" );
ImageSpan span = new ImageSpan( context, img.drawable );
stringBuilder.setSpan( span, img.idx, img.idx + 1, 0 );
}
holder.mText.setText( stringBuilder );
// none of this helps
holder.mText.forceLayout();
holder.mText.requestLayout();
holder.mText.invalidate();
Here's the relevant part of the layout for each list item:
<?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">
<LinearLayout
android:id="#+id/speech_bubble"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#drawable/speech_bubble_right"
android:layout_marginLeft="40dp"
>
<TextView
android:id="#+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:layout_toRightOf="#id/timestamp"
/>
</LinearLayout>
</RelativeLayout>
I tried invalidating and forcing a layout on the TextView parent (LinearLayout) but it did nothing.
I tried editing the layout down to literally just this:
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
/>
.. and the problem still happens. It's definitely the fault of TextView itself.
I'm guessing that the issue here isn't with the measurement of the TextView, but rather, the measurement of the TextView's container (some ViewGroup - perhaps a LinearLayout?).
If this ViewGroup's layout params is set to WRAP_CONTENT for the height, then for some reason, the height isn't being calculated again on time. To solve this, try the following:
int widthMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY);
int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
holder.mContainer.measure(widthMeasureSpec, heightMeasureSpec); // perhaps a simple call to requestLayout or forceLayout will be enough?
If you know the exact height the cell should be, you can use that as well - simple replace the line where I calculate the heightMeasureSpec with the following:
int heightMeasureSpec = MeasureSpec.makeMeasureSpec(calculatedHeight + topPadding + bottomPadding, MeasureSpec.EXACTLY);
Hope this helps.
Got a little bit tricky
setTextSize(someDifferentSize);
setTextSize(normalSize);
Seems like it is some kind of line height problem, happened when image span is taller than it. I will dig into that if I have time.

Android get Fragment width

I have a layout with 3 fragments:
<LinearLayout android:id="#+id/acciones"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<LinearLayout
android:id="#+id/fragment1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
</LinearLayout>
<LinearLayout
android:id="#+id/fragment2"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:id="#+id/f3"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
</LinearLayout>
</LinearLayout>
In the first fragment I have a TableLayout in which I have one custom TextView in each row.
I want to know the width of the fragment because if the custom TextView is wider than the fragment, I'll set the number of lines necessary.
This is what I've done in my custom TextView:
#Override
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mMaxWidth = (float) (getMeasuredWidth());
}
With this line I got the width from the three Fragments, not only the one which contains the custom TextView.
Thanks.
You should be able to set the width of the TextView to be fill_parent, in which case it will do the wrapping for you. You should not set the widths of your layouts to be match_parent since it is inefficient when you're using layout weights.
Since android's layout system is occasionally mysterious with regards to view sizes, if setting the TextView width to be fill_parent actually makes it take up the whole screen (as your question appears to be implying) do the following:
Set your TextView width to 0 by default. In onCreate of your activity, after setting the content view:
findViewById(R.id.acciones).getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
final int fragmentWidth = findViewById(R.id.releventFragmentId).getWidth();
if (fragmentWidth != 0){
findViewById(R.id.yourTextViewId).getLayoutParams().width = fragmentWidth;
}
}
});
By setting the TextView's width to 0 initially, you prevent it from changing the widths of the fragments. Then you can use a view tree observer to get the width of whatever fragment you're interested in (by looking at its root view) after layout has occurred. Finally you can set your TextView to be that exact width, which in turn will do the wrapping for you automatically.
Note that onGlobalLayout can be called multiple times and is regularly called before all of the views have been completely laid out, hence the != 0 check. You will also probably want to do some kind of check to make sure that you only set the width of the text view once, or otherwise you can get into an infinite layout loop (not the end of the world, but not good for performance).

Fullscreen App, Layout shifted down by height of notification bar

I have an App that has a toolbar at the bottom of the screen and the rest is filled with a custom View (see xml below). Now when I make the App full screen (I tried all possibilities, programmatically and via Manifest.xml), when it's started the whole layout seems to be shifted down by about the height of the notification bar. The buttons in the toolbar are only visible half-way. Sometimes, all of it moves up after a few seconds, or when I click a button in the toolbar.
I'm pretty sure, that it's a problem with my custom view, because I do not get this effect if I replace it with a Button or the like. I guess it must have something to do with the onMeasure method. I don't really know how to implement it, my version is shown below. The custom view is used for drawing inside, so basically it wants to be as large as possible.
Any help would be much appreciated. I searched for several hours already, but no clue yet.
layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<com.example.MyCanvasView
android:id="#+id/canvas"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
/>
<!-- Buttonbar -->
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingTop="4dp"
android:orientation="horizontal"
android:background="#android:drawable/bottom_bar"
>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="2"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="3"
/>
</LinearLayout>
</LinearLayout>
And this is my onMeasure method:
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width, height);
}
You're not taking the mode into account when you're setting your measurement.
The mode of a MeasureSpec can be one of MeasureSpec.EXACTLY, MeasureSpec.AT_MOST, or MeasureSpec.UNSPECIFIED. Simply accepting the size component and setting your measured size to that is appropriate for EXACTLY, but it isn't often the right thing for the others.
Because you're trying to use layout_weight in addition to a height of wrap_content on this custom view, the following is happening:
Your custom view is the first child of the LinearLayout with a height of wrap_content so LinearLayout measures it. Since LinearLayout has been told by the LayoutParams that it should wrap_content, it measures your custom view with a MeasureSpec mode of AT_MOST and a size of the entire available space.
But your custom view is greedy. It decides to take all of the space available. In essence, you have implemented your measurement to treat wrap_content as match_parent.
Now there's no more space left. The lower button bar gets measured accordingly but it's not done yet, there's a child with weight. In a LinearLayout any space left over after all normal measurement is complete is divided among the weighted children according to their weight values. This isn't the behavior you want.
When you use weight to fill available vertical space like you're doing in this layout, you normally want to set the layout_height to 0dip. This will make LinearLayout skip the first measure pass on that child and only use the weighted measurement pass to measure your view, giving it the remaining available space.
I found the reason for the described behaviour. I had set the view to be focusable in touchmode via setFocusableInTouchMode(true) in the onCreate() method. As soon as I removed this, it works fine. Thanks to adamp though -- your description of what goes on during layout and measuring was very interesting.
But that leaves me with the problem that I do not receive any key/button clicks any more :-(

Categories

Resources