Android ViewPager center item on screen - android

I am trying to show a dialog over my screen. And that dialog should have ViewPager in it with FragmentPagerAdapter. Each item in adapter has width set to .7f. What is important to me is that when some item is selected it should be snapped to center of the ViewPager with parts of next and previous fragments visible (exactly as image shows). Unfortunately the default behavior is snap to the left.
Is there any way of achieving it please?
Thank you
(Just if anybody asks: On that picture the ViewPager is not stretched over dialog. In real the dialog matches parent's width and is layouted the way so it doesn't look like it)

Just in case anyone is looking for the same thing, I've come to solution:
Simply set left and right padding to ViewPager and then set clipToPadding to false. That will result into one fragment to be centered and pieces of neighbor fragments in sides as it is in picture. Then to add space between fragments use viewPager.setPageMargin(); in code.
That's it :)
EDIT://
Here is some sample code
<android.support.v4.view.ViewPager
android:id="#+id/viewPager"
android:clipToPadding="false"
android:paddingLeft="40dp"
android:paddingRight="40dp"
android:layout_width="match_parent"
android:layout_height="match_parent" />
ClipToPadding=false ensures that fragments will be drawn even when they are positioned out of the viewPager's content area.
And then in code add spaces between viewPager's items:
mViewPager.setPageMargin(100);
Please note that setPageMargin takes number of pixels as parameter, not number of display points. You probably should convert some dp value to pixels to have correct spacing across all devices. This method should work fine:
public static float dipToPixels(Context context, float dipValue) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dipValue, metrics);
}

I was facing a similar issue and no one tried to approach it this way, it might not be completely accurate but visually looks centered.
Use DisplayMetrics to get the device height dimension, and then set the padding for your viewpager as follows:
int height = Resources.getSystem().getDisplayMetrics().heightPixels;
pager.setPadding(0,height/6,0,0);
Note that the layout of the items of the viewpager must be set to "wrap_content" and viewpager in the activity/fragment's height must be "match_parent".
In my case, height/6 as the top padding makes it look centered. Play around with this number for your best results.

Related

How to set a constraint layout width of an item in a recyclerview to a percentage of the parents width, not a fixed dp value?

I have a problem with recyclerview items width:
i already looked through android docs and stack so i think, there is no solution to this problem.
i have an ordinary recyclerview with a horizontal gridlayout
sorry, but i dont have enough reputation to embed pictures
Picture of recyclerview
and i want the items of it being shown next to each other, but I want to make the width of the items depend on the width of the parent (in this case, the recyclerview width used in the other fragment).
I can show you what i want by using a fixed value (in this example 200dp)
Picture of the solution I want, but here a fixed value for width is used
However if my constraint of the item is set to "match parent" like here:
Picture constraint set to match parent
The result is, that the width of the items seen in the phone always depends of the width of the recyclerview. in my case its cut nearly in half:
recyclerview cut in half
also android studio only allows one view as a top level layout, so i cannot use a guideline that is set to any %
possible solution to that?
If you have width of recycler view (in pixel not dp), just divide it by number of items in a row, and in your adapter in "onBindViewHolder" method set item width. this solution is when all of your item has same width.
In addition for height of every item use WRAP_CONTENT.

How do I create a ViewPager without margins?

Using the ViewPager view from the Android support library, the default setup shows one page at a time, with a large margin between each item - ie, if your view is about half the width of your activity there's space on either side, and as you swipe the next one in there's space there too.
ViewPagers have a method, setPageMargin(), that lets you specify an offset to adjust the margin size between pages, and I'm using it to specify a negative margin so that it pulls the pages closer together. However, obviously the amount you need to pull in these margins varies according to the screen dimensions.
So, I'm looking for a smarter way: is there a way to tell the ViewPager "I want no margins at all, making the views in my ViewPager butt up against each other"?
Thank you!
I don't know if there's a smarter way, but your way should work if all pages have the same width. Try something like this:
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
// getActivity().getWindow... if inside a Fragment
yourViewPager.setPageMargin((yourPageWidth - dm.widthPixels) / 2);

Using relativelayout with absolute positions

I know I can use margins to do that but I am getting some problems when objects are near edge of the screen. In this case android tries to fit all contents of view into screen which is something I don't want. For example if I give 200 width to a view and 100px of this is outside the screen it fits it to
100 px.
How can I avoid this?
Also why AbsoluteLayout is deprecated? I am currently working with it and it works but I wonder if people will throw stones at me
Without seeing your actual layout, it sounds like you want to have content that is offscreen. If you would like the user to be able to see that content, you could use a scroll view. That way, when you start your activity, your stuff will show up as you've laid out, with any overflow offscreen, and then the user can scroll over to it as desired.
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal">
<!--your stuff here -->
</LinearLayout>
</HorizontalScrollView>
Otherwise, if it's an image, there are various cropping and alignment options that could cover what you want.
Use RelativeLayout. Then just perform a simple check when adding View to RelativeLayout. For instance remember the last lastX & lastY location of added View and then check whether lastX + newView.width() <= RelativeLayout.width(). True -> add it, False -> set Y coordinate of newView to something like lastY + HEIGHT + BOTTOM_MARGIN and lastX back to 0
In the end I just added some negative paddings to my relative layout. Thanks to these paddings, views does not try to fit themselves into screen

How to create two views in Android that use 50% height each, unless one is smaller?

Imagine a full Android device screen, I want it split in to two sections:
The upper half has text in it, which may be larger than the space available (or not) and so the text will scroll (i.e. TextView inside a ScrollView)
The lower half contains a MapView control.
Looking specifically at some scenarios:
If the text is small, I want the map to take up more space, i.e. more than 50%. So perhaps 20% text, 80% map.
If the text is larger, it only takes up a MAXIMUM of 50% of the screen space, and then scrolls. So 50% map, 50% text.
At the moment I've assigned weights to the two parts, and that isn't too bad, but if the text is small, the map doesn't expand to take the space, and the layout has a wasted gap that the map could usefully use.
I've tried loads of combinations but can't see how to make this happen. It seems to be a common experience for me that I know what I want, but can't see how to get the available views to deliver it. I'm hoping there's a nice easy way to do this.
Please feel free to make me look like a fool and point out the obvious attribute I've missed :-)
======================================================================
As far as I can see there's no way to do this just in declarative XML and it needs doing in the code. I set the text section height to wrap_content, weight to 0 (no resizing), and have the map set to weight=1 (i.e. take up the remaining space). I then check if the text section (in a ScrollView) is taking up too much space and if so, shrink it back. This code would need changing to support a different layout orientation.
private void fixLayoutProportions()
{
float maxPercentageOfScreenForText = 50/100;
LinearLayout container = (LinearLayout)findViewById(R.id.container);
ScrollView eventText = (ScrollView)findViewById(R.id.text_scroller);
int heightAvailable = container.getHeight();
int scrollerHeight = eventText.getHeight();
if ( scrollerHeight>(heightAvailable*maxPercentageOfScreenForText) ) // Text section using too much space
{
eventText.getLayoutParams().height = (int)(heightAvailable*maxPercentageOfScreenForText) ;
eventText.invalidate();
}
}
You can do it by putting everything into LinearLayout and changing following parameters:
the sum of weights for LienarLayout
weights for children
Did you try to measure your screen hight at run time:
Display display = ((WindowManager)
getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
int width = display.getHeight();
Then, set your top view max_height to width*0.5 and min_height to width*0.2. Your top view has to be control (like TextView) that has min_height and max_height properties. Also, set layout_weight to 0 or leave it empty.
On your bottom view set layout weight to 1.
The easiest way to do 50/50 is in XML is using LinearLayout weights. Basically put the two views into a single LinearLayout set the android:layout_weight on both child views to the same value, like setting both to .5, 1, or 42. You then set the layout_width to 0px or fill_parent/match_parent.
The smaller part gets more complicated. Luckily, you can turn off weighing in Java. One way is to wait until the windows get drawn (if they are pre-populated) and measure them. This can be done on I think it was called onWindowFocusChanged
I haven't tested this, but I'd try setting your ScrollView to have android:layout_weight="1" and your MapView to have android:layout_weight="0" and a android:minHeight="240dp". The hope is that minHeight will have precedence over layout_weight.
i think you have to set mapviews height as fill parent and set textviews height as wrap contetn and than for scrolling you have toset vertical scrool true for text view and as you nedded not more than 50% space textview you can set maxheight property of textview.
I am sorry if you find this trivial.
But I am suggesting it in case it did not strike you.
How about using relative layout and keeping the textview always on top of the map.
Make the gravity of the textview top, its width match_parent, its height wrap_content and its weight 1(same as that of thee map). That way your textview will change according to the size of the text, while not going above 50% because of the weight. As for the map, the user can pull the map down to see the hidden part under textview. It'll be as if there is no map under the textview(you know, unless you want to make the textview background transparent which i think would look cool :) ). I do not know about the map view. But I am assuming it'll be something like google maps on iphone, like you can vary size using multi-touch and scroll using single.
OK as I see its something like u are reserving at max half of ur screen to the TextView and if its more it has to scroll. I have a solution but for that you will have to fix the max no.l of lines for TextView, calculating which can be a pain :P but have a solution never the less.
main.xml file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical"
android:maxLines="5"
android:id="#+id/tv1"
android:text="wsdvsv sjdgv jsdvn ksdjbn skjdb ksdnbk snbk snbjksn fkbj sfkbjn dfkjbndkjfbn kdjfnb kjdfnbkjdnfbk ndf bjkndf bndfjbn dfkbn jdfnbjdfnbjdfn bjdf nbkjdnf bkjdfnb kjdnfbkjdfn bkjndfbjndfjbndkjfbn dkfjbn kdjfnb kjdfnbkjdfnbjkd nfkjbndf"
/>
<TextView
android:layout_width="fill_parent"
android:layout_below="#id/tv1"
android:layout_height="wrap_content"
android:scrollbars="vertical"
android:maxLines="5"
android:text="Does it work ???"
/>
</RelativeLayout>
Java file:
package com.android;
import android.app.Activity;
import android.os.Bundle;
import android.text.method.ScrollingMovementMethod;
import android.widget.TextView;
public class TestActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView tv = (TextView) findViewById(R.id.tv1);
tv.setMovementMethod(new ScrollingMovementMethod());
}
}
If the text is say only in 2 lines "Does it work?" will shift up automatically. But the only problem i see here is the max lines to 5 is you can an max value for u i guess this might work well :)
BR,
J
P.S. I haven't answered many questions before so i m not sure how to attach files :(

How to create a view that is bigger than the screen?

Is it possible to create a view that is bigger than the screen?
I need a view that has a bigger width then the screen of the device. I use this view in a rotation animation. During the rotation the parts that were not on the screen before animating the view will become visible.
Is there a way to achieve this effect with the android framework?
Update
I tried to set my parent layout much bigger then the screen and it is working. This will make somethings a little bit uncomfortable but it could work. The next problem now is that my layout still starts at the left side of the screen. I can't think of a method to make the layout to expand itself to the left and the right of the screen.
Ok I got an answer. It is not very nice because it uses a deprecated View class but it works at least on my current testing screen resolution other resolutions are tested tomorrow.
I wrapped the view that I wanted to expand beyond the screen in an absolute layout like this:
<AbsoluteLayout
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentBottom="true">
<ImageView
android:id="#+id/content"
android:layout_width="600dip"
android:layout_height="420dip"
android:scaleType="centerCrop"
android:layout_x="-200dip"
android:layout_y="60dip"
android:src="#color/testcolor" />
</AbsoluteLayout>
The -200 x coordinate makes the view stick 200dip out of the left side of the screen. If I'm animating the view those parts that are outside the screen will gradually become visible.
E.g. setting negative bottom margin together with setting extra large layout_height (large enough for you) solved the similar issue as for me.
Works fine at least using API 11+ animations/rotations.
Could look like:
android:layout_marginBottom="-1000dp"
android:layout_height="1000dp"
In case anyone still comes up on this page. The key is your root layout, it will only work with a FrameLayout (or the deprecated absolutelayout). Then you have two options to make your child view bigger.
through xml, this is quick and easy but you don't know the actual screen width & height in advance so your off with setting a ridiculously high value for layout_width & layout_height to cover all screens.
Calculate the screen size programatically and make the view's width/height proportional bigger to this..
Also be aware that your bigger view still starts in the top left corner of the screen so to account this you will have to give a negative top & left margin that's half of what you are adding to the view's width/height
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) viewToMakeBigger.getLayoutParams();
int marginLeft = (int) (viewToMakeBigger.getWidth()*0.1);
int marginTop = (int) (viewToMakeBigger.getHeight()*0.1);
params.width = (int) (viewToMakeBigger.getWidth()*1.2);
params.height = (int) (viewToMakeBigger.getHeight()*1.2);
params.leftMargin = -marginLeft;
params.topMargin = -marginTop;
viewToMakeBigger.setLayoutParams(params);
HorizontalScrollView:
http://developer.android.com/reference/android/widget/HorizontalScrollView.html
Layout container for a view hierarchy that can be scrolled by the user, allowing it to be larger than the physical display.
The simple axml below creates an ImageView that is 400dp wider than the screen (even though the layout_width is set to equal the parent's width) using a negative left and right margin of 200dp.
The ImageView is situated 250dp above the top of the screen using a negative top margin, with 450dp of 700dp vertical pixels visible on the screen.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:background="#FFFF0000"
android:layout_height="700dp"
android:layout_marginLeft="-200dp"
android:layout_marginRight="-200dp"
android:layout_marginTop="-250dp"
android:layout_width="match_parent" />
</RelativeLayout>
You can override the views in the onMeasure method. This will set your View dimensions to 1000x1000 px.
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(1000, 1000);
}
Is it possible to create a view that is bigger than the screen?
Why not, you can define the layout_width and layout_height in px(or dip) as you want:
android:layout_width="10000px"
android:layout_height="20000px"
You need to change the size of the window, by getWindow().setLayout. This will increase the size for your window. Since the root layout can be as big as its parent you can then increase the size of the view you want to be bigger than the screen size. It works for me let me know
You can use ViewSwitcher to handle that. Used with Animation and a OnGestureListener looks pretty good.
You can do it programmatically:
FrameLayout.LayoutParams rootViewParams = (FrameLayout.LayoutParams) rootView.getLayoutParams();
rootViewParams.height=displayMetrics.heightPixels+(int)dpToPixels(60);
rootViewParams.width=displayMetrics.widthPixels+(int)dpToPixels(60);
rootView.setLayoutParams(rootViewParams);
rootView.setX(rootView.getX() - dpToPixels(30));
rootView.setY(rootView.getY() - dpToPixels(30));
MUST BE ONLY IN
"public void onWindowFocusChanged(boolean hasFocus)" method.
and
rootView = (RelativeLayout) findViewById(R.id.rootLayout);
Inside "protected void onCreate(Bundle savedInstanceState)" method.
Where yout .xml file is like this:
<RelativeLayout
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:id="#+id/rootLayout"
tools:context="com.example.Activity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_centerHorizontal="true"
android:layout_margin="30dp"
android:layout_centerVertical="true"
android:layout_height="match_parent">
// Bla bla bla
</RelativeLayout>
and:
public float dpToPixels(float dp) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics());
}

Categories

Resources