when rotate how to dynamically change layout to avoid re-start activity - android

Having a layout which has horizontally side by side A and B parts when in landscape mode. Let's say A take 1/3 of the screen and B take other 2/3.
When rotate what is wanted is that the A keeps its original width but is changed to overlay on top of the B and B changes to have width of full screen underneath the A.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<FrameLayout
android:id="#+id/left_part"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.3" />
<FrameLayout
android:id="#+id/right_part"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.7" />
</LinearLayout>
The part A, and B are holders for different fragments, which has it's adapetr with cursor etc. and could have a few stacked up in backstack. So when rotate would prefer to not re start the activity so that the context is maintained, but just some how to rearrange the layout dynamically.
Not sure if it is doable. Any suggestion?
Thanks!

Handling the Configuration Change Yourself

Your activity should be using saved instance state to persist the data from the old layout and restore it into the new layout.
It's theoretically possible to define a single layout that has sub groups from the different orientations, populate them both, then show / hide those as the rotation occurs using the method mentioned above for handling it yourself, but you are better off sticking Android's stock mechanism to handle this.

seems it should work with dynamically changing the layout, tried following shows the expected behavior.
Please comment if seeing any issue with this approach or having better solution. Thanks!
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<FrameLayout
android:id="#+id/right_pane"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:layout_alignParentLeft="false"
android:layout_toRightOf="#+id/left_part" />
<FrameLayout
android:id="#+id/left_part"
android:layout_width="#dimen/left_part_width"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"/>
</RelativeLayout>
void doChangeMode() {
RelativeLayout.LayoutParams leftLp = (RelativeLayout.LayoutParams) leftPart.getLayoutParams();
RelativeLayout.LayoutParams rightLp = (RelativeLayout.LayoutParams) rightPart.getLayoutParams();
if (mode == mode_side_by_side) {
mode = mode_overlap;
rightLp.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
} else {
mode = mode_side_by_side;
rightLp.addRule(RelativeLayout.ALIGN_PARENT_LEFT, 0);
//api 17 above
//rightLp.removeRule(RelativeLayout.ALIGN_PARENT_LEFT);
}
Handler delayHandler = new Handler();
delayHandler.post(new Runnable() {
#Override
public void run() {
rootView.requestLayout();
}
});
}

Related

How to resize View with pull the edge gesture?

I am looking for solution as on images bellow:
I need to have two resizable views in one layout.
User just needs to move separation line to the top (ScrolView B becames higher) or to the bottom (ScrolView A becames higher).
What is the best solution, which gives this behavior? I know that I can extends from ScrollView and override public boolean onTouchEvent(MotionEvent ev) and protected void onDraw(Canvas canvas), but may be there is more simple solution. I want to avoid calculation the math of moving. Thank you for any information.
If you want to solve this problem quickly, I suggest you use Split Pane Layout.
Usage :
<com.mobidevelop.spl.widget.SplitPaneLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:spl="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:id="#+id/splitPaneLayout"
android:layout_height="match_parent"
spl:splitterSize="12dp"
spl:orientation="vertical"
spl:splitterPosition="50%"
spl:splitterBackground="#781b23">
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="" />
</ScrollView>
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:text=""/>
</ScrollView>
</com.mobidevelop.spl.widget.SplitPaneLayout>
I solved your problem by creating two xmls for portrait and landscape mode. For portrait mode, i set the panel's orientation as vertical by adding spl:orientation="vertical" and for lanscape mode, i set the panel's orientation as horizontal by adding spl:orientation="horizontal".
After doing all this, I got the look like below.
Made this into an answer.
You basically want the split screen view from Android N. You could base your code off the open source implementation in SystemUI:
http://androidxref.com/7.1.1_r6/xref/frameworks/base/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
Along with this for the handle:
http://androidxref.com/7.1.1_r6/xref/frameworks/base/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java
You can throw away all code that has to do with stacks (which is the row of screenshots off different activities in your history), buss events and anything that has to do with running another activity, such as the code for Vsyncing between apps (mSurfaceFlingerOffsetMs).
It should leave you with quite small and easy to use classes.

How to use two activites in a single screen in android?

I want to display two different activities in a single screen how can i do that in android?Please if anybody has idea share it.And I don't wanna use fragments.
I want to display a screen which contains some fields and below(at the bottom of the screen) I want another screen with some buttons.
Is this possible in android?
If so, How can i do this ?
You can't have two activities in one screen. You can have only one. So, ultimate solution is Fragments.
An activity is not directly a visual component, so I'm thinking that what you're really asking is how to have a single activity display different views.
There's nothing that says you can't rerun setContentView() with a different layout/view ID. But there's another non-fragments way of doing what your probably want.
You can define more than one full-size (match_parent) view in a layout. What you want to do is set the visibility for one of them to "visible" with android:visibility="visible" and all the others to "gone" with android:visibility="gone".
Then when you want to switch the displayed view, you'll run setVisibility(View.GONE) on the outgoing view and setVisibility(View.VISIBLE) on the incoming. It's important to use GONE and not INVISIBLE or the layouts won't render correctly.
Sample layout file:
<FrameLayout 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"
tools:context=".MainActivity" >
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:id="#+id/img"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible" />
<SurfaceView
android:id="#+id/video"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
<WebView
android:id="#+id/web"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
</FrameLayout>
Sample Code to switch view:
video.setVisibility(View.VISIBLE);
img.setVisibility(View.GONE);
web.setVisibility(View.GONE);
That said, you probably want to learn how to use fragments since you can handle switching the view along with other state in a single unit of work (a transaction). But the above approach above does work for simple view changes.

Detect click on screen when in landscape

I'm having some trouble with detecting screen clicks on the GUI. Works in portrait but fails in landscape, see below.
I have a GUI (Fragment) which contains some instructions + images. The user is required to tap anywhere on the screen to proceed. In order capture the click/tap event, I have put in a View(topview) that fill the entire screen and sits onto of other elements, I then listen for clicks on this view and it works fine.
The problem is when in landscape mode, the text and images take up to much room. So the whole thing is now wrapped in a ScrollView. This is where the problem begins. When the ScrollView is active, (i.e. you can scroll/scroll bars are visible), my view on top (topview) disappears. It seems that when in landscape mode the height of content in a ScrollView is being changed. As an experiment I replaced the View with a Button and the Button goes from filling the screen in portrait to being normal height in landscape mode when the ScrollView is usable.
Is there a way of me detecting the user tapping on the screen, which works with the ScrollView control as the top element. I've tried rearranging the GUI in several ways but without success, and I've tried adding onClick event handlers to the ScrollView, also without success.
My Layout is below, note my top view is semi-transparent red, so I could see the area it covered.
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:clickable="true" >
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:orientation="vertical" >
<TextView
android:id="#+id/txtInstructions"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal|center_vertical"
android:padding="10dp"
android:text="#string/instructions"
android:textColor="#color/blue"
android:textSize="20sp" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:maxWidth="250dp"
android:padding="20dp"
android:src="#drawable/main_camera" />
</LinearLayout>
<View
android:id="#+id/view_to_listen_for_touch"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#88FF0000"
android:clickable="true" />
</RelativeLayout>
One thing that works(although looks like more like a hack(pretty ugly)) is to programatically add the special View in code(in the onCreate method) and set its dimensions based on the parent RelativeLayout's exact dimensions. Here is a snippet of code:
//...
final RelativeLayout parent = (RelativeLayout) findViewById(R.id.ff);
final View layer = new View(this);
layer.setBackgroundColor(Color.parseColor("#88FF0000"));
// the ScrollView really doesn't like this View ,using this without the
// runnable will not work
layer.setLayoutParams(new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT,
RelativeLayout.LayoutParams.MATCH_PARENT));
layer.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(), "SDFD",
Toast.LENGTH_SHORT).show();
}
});
parent.addView(layer);
// this is required because if we use directly the getWidth/getHeight we
// will get 0/0
layer.post(new Runnable() {
#Override
public void run() {
layer.setLayoutParams(new RelativeLayout.LayoutParams(parent
.getWidth(), parent.getHeight()));
}
});
//...

Android - vertical orientation works, horizontal orientation blank

I am implementing a ViewPagerIndicator that works as expected in vertical orientation. When I test in horizontal orientation, either by switching at run-time (physically turning the phone) or when the app starts in horizontal mode (phone was horizontal before the app started) I get a blank white space where the ViewPagerIndicator should be. I have a layout/main.xml and layout-land/main.xml with a few buttons that are displaying as expected (stacked vertically in vertical mode, as a grid in horizontal mode). When I press the "edit" button, I launch the edit activity:
public class ATEditActivity extends Activity {
static final int OFFSCREEN_PAGE_LIMIT = 5;
ViewPager pager = null;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.edit);
int iPage = 2; // set the page based on caller's intentions
Bundle bndlExtras = getIntent().getExtras();
if (bndlExtras != null) {
iPage = bndlExtras.getInt("PAGE");
}
ATViewPagerAdapter adapter = new ATViewPagerAdapter(this);
pager = (ViewPager) findViewById(R.id.awesomepager);
pager.setOffscreenPageLimit(OFFSCREEN_PAGE_LIMIT);
pager.setAdapter(adapter);
TitlePageIndicator indicator = (TitlePageIndicator) findViewById(R.id.TitlePageIndicator);
indicator.setViewPager(pager);
indicator.setCurrentItem(iPage);
}
}
edit.xml:
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:background="#FFFFFF"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginLeft="0dp"
android:layout_marginRight="0dp">
<EditText
android:id="#+id/etName"
android:inputType="textAutoComplete"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/edit_text"
android:layout_margin="4dp"
android:hint="#string/name" />
<com.viewpagerindicator.TitlePageIndicator
android:id="#+id/TitlePageIndicator"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
style="#style/Widget.MyTitlepageIndicator" />
<android.support.v4.view.ViewPager
android:id="#+id/awesomepager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Any thoughts on why the ViewPagerIndicator would not display in horizontal mode? Is more information needed?
You probably need to override onConfigurationChanged() see reference as your app needs to retrieve the resources again and draw everything.
After three or four days of trying everything I could imagine, I finally decided there must have been something really messed up in my project so I created a new project that only had the minimal amount of code necessary to get the ViewPagerIndicator working. The new project is now working with both orientations "out-of-the-box". I have no idea what caused my old project to go haywire with only the horizontal orientation but I will get the new project on track and up to speed in short order now that it is working as expected.

How to force a redraw of the views in Activity.onConfigurationChanged

I've got three views in my activity in a linear vertical layout. The top and bottom views have fixed heights and the middle view takes whatever height is left available. This is how I set the sizes for the views:
void resize(int clientHeight)
{
int heightMiddle = clientHeight - heightTop - heightBottom;
topView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, heightTop));
middleView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, heightMiddle));
bottomView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT));
}
In order to obtain the clientHeight, I overrode the onMeasure() function and call resize() inside my overridden onMeasure() function. This works well in onCreate(). However when the phone orientation changes, it does not work. What I observed is that after onCreate(), onMeasure() is called twice. After onConfigurationChanged(), onMeasure() is only called once and my resizing code does not get a chance to take effect. My kluge solution is to setup a timer to call resize() 20ms later:
timer.schedule(new TimerTask()
{
#Override
public void run()
{
activity.runOnUiThread(new UiTask());
}
}, 20);
where UiTask will simply call resize(). This works for me, but I feel that there's got to be a better solution. Can someone shed some light on this?
Why not let LinearLayout do the layouting with the help of the android:layout_weight attribute? That way, you don't need any extra code at all, everything will just work. Here's what your res/layout/main.xml could look like:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="Top"
android:layout_weight="0"
android:background="#ff0000"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Middle"
android:layout_weight="1"
android:background="#00ff00"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="25dp"
android:text="Bottom"
android:layout_weight="0"
android:background="#0000ff"
/>
</LinearLayout>
And with no more code other than the regular
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
it would look like this in portrait:
and like this in landscape (automatically relayouted and redrawn):
This works both with and without android:configChanges="orientation" for the activity in the manifest. You'll also be able to setup the above layout using Java code if you need to.

Categories

Resources