i'm creating my view programmatically, no xml at all and need the real size of the area i'm working in. i have been using this code:
public static class DummySectionFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (container == null) {
return null;
}
Context context = getActivity();
int tabNo = getArguments().getInt(ARG_SECTION_NUMBER);
Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
// check display size to figure out what image resolution will be loaded
DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics(metrics);
Point size = new Point();
display.getRealSize(size);
display.getSize(size);
int width = size.x;
int height = size.y;
but that doesn't take into account all the other 'decoration' like title bar and nav bar
the docs say not to use display metrics to get the size but how can i find out the size of the view in onCreateView? i tried container.getHeight() but that returns 0
i guess the issue is the view hasn't been created yet but there must be a parent to onCreateView that knows how big the view will be right?
how do i find that?
thanks
FYI, this works:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (container == null) {
return null;
}
Context context = getActivity();
int tabNo = getArguments().getInt(ARG_SECTION_NUMBER);
Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
// check display size to figure out what image resolution will be loaded
DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics(metrics);
Point size = new Point();
display.getRealSize(size);
display.getSize(size);
int width = size.x;
int height = size.y;
switch (metrics.densityDpi) {
case DisplayMetrics.DENSITY_XXHIGH: height -= 72; break;
case DisplayMetrics.DENSITY_XHIGH: height -= 64; break;
case DisplayMetrics.DENSITY_HIGH: height -= 48; break;
case DisplayMetrics.DENSITY_MEDIUM: height -= 32; break;
case DisplayMetrics.DENSITY_LOW: height -= 24; break;
default:
Log.e("onCreateView", "Unknown density");
}
}
but it doesn't seem like a clean way to do it. i guessed the xhigh and xxhigh, i haven't found the actual numbers yet
ALSO i should add that the view is created from onTabSelected in the MainActivity like this
#Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
// When the given tab is selected, show the tab contents in the
// container view.
Fragment fragment = new DummySectionFragment();
Bundle args = new Bundle();
args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, tab.getPosition() + 1);
fragment.setArguments(args);
getSupportFragmentManager().beginTransaction().replace(R.id.container, fragment).commit();
}
i think i have it
i think getSize returns the realsize minus the navigation bar, so i need to subtract the action bar
so now i do this:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (container == null) {
return null;
}
Context context = getActivity();
int tabNo = getArguments().getInt(ARG_SECTION_NUMBER);
Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
// check display size to figure out what image resolution will be loaded
DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics(metrics);
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
TypedValue tv = new TypedValue();
int actionBarHeight=0;
if (context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true))
{
actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data,getResources().getDisplayMetrics());
}
height -= actionBarHeight;
//Log.d("MainActivity", "onCreateView tabNo="+tabNo +" display width="+width+" height="+height+" rotation="+rotation);
switch(tabNo){
case 1:
return onCreateViewScoreFragment(context, width, height);
case 2:
return onCreateViewFilesFragment(context, inflater, width>height);
default:
return onCreateViewSettingsFragment(context, inflater, width>height);
}
}
it works on my tablet, i'm not 100% sure about other devices, i'll have to wait and see what my customers say
Related
I have a problem in relation to the relative location of Buttons in different devices. I have done a short application to show it. The Button, in relation to a red point, behaves as desire when dealing with wide measures (coordinate x). However, I don’t know why the same Button is progressively scrolling down from the red point (coordinate y) as I choose a smaller device. I choose the right size of the image for the different devices and for both, wide and height, I also choose the relative measure of the screen:
rel_btn.width = 4*width/100;
rel_btn.height = 7*height/100;
I show you the code and the resulting screen of the xlarge screen in case someone can help me:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//width and height of the screen
DisplayMetrics metrics = new DisplayMetrics();
WindowManager windowManager = (WindowManager) MainActivity.this.getSystemService(Context.WINDOW_SERVICE);
if (windowManager != null) {
windowManager.getDefaultDisplay().getMetrics(metrics);
}
int width = metrics.widthPixels;
int height = metrics.heightPixels;
RelativeLayout layout = (RelativeLayout) findViewById(R.id.test); // id del XML
RelativeLayout.LayoutParams rel_btn = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
rel_btn.width = 4*width/100; rel_btn.height = 7*height/100;
// x, y of the BUTTON
rel_btn.leftMargin = 15*width/100; rel_btn.topMargin = 66*height/100;
Button btnTag = new Button(this);
btnTag.setLayoutParams(rel_btn);
btnTag.setBackgroundColor(Color.TRANSPARENT);
btnTag.setId(0); // writes the ID
btnTag.setOnClickListener(prueba);
layout.addView(btnTag);
}
private View.OnClickListener prueba = new View.OnClickListener() {
#Override
public void onClick(View view) {
//width of the screen
DisplayMetrics metrics = new DisplayMetrics();
WindowManager windowManager = (WindowManager) MainActivity.this.getSystemService(Context.WINDOW_SERVICE);
if (windowManager != null) {
windowManager.getDefaultDisplay().getMetrics(metrics);
}
int width = metrics.widthPixels;
Button button = (Button) view;
GradientDrawable drawable = new GradientDrawable();
drawable.setShape(GradientDrawable.RECTANGLE);
drawable.setStroke(Math.round((float) (0.6*width/100)), Color.BLUE);
drawable.setColor(Color.TRANSPARENT);
button.setBackgroundDrawable(drawable);
}
};
}
Same problem, don't know if this counts as a duplicate.
I have a problem with Android's StaggeredGridLayoutManager. The description of the problem is pretty much the same with StaggeredGridLayoutManager dislocation.
Here's the screenshot (sorry for the censorship, those are CardViews):
And the adapter:
public class ProductItemStaggeredAdapter extends RecyclerView.Adapter<ViewHolderRVProductItem> {
public ProductItemStaggeredAdapter(RealmResults<ProductItem> items, int theme) {
mItems = items;
this.theme = theme;
setHasStableIds(true);
}
#Override
public ViewHolderRVProductItem onCreateViewHolder(final ViewGroup parent, final int viewType) {
Context context = parent.getContext();
int blackGrey1 = ContextCompat.getColor(context, R.color.black_grey1);
int white = ContextCompat.getColor(context, R.color.white);
LayoutInflater inflater = LayoutInflater.from(context);
View view;
ViewHolderRVProductItem vh = null;
switch (viewType) {
case 100:
/** Error **/
view = inflater.inflate(R.layout.item_retry, parent, false);
StaggeredGridLayoutManager.LayoutParams lp3 = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
lp3.setFullSpan(true);
view.setLayoutParams(lp3);
view.setOnClickListener(retryClickListener);
vh = new ViewHolderRVProductItem(view);
break;
case 101:
/** Loading **/
view = inflater.inflate(R.layout.item_loading, parent, false);
StaggeredGridLayoutManager.LayoutParams lp4 = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
lp4.setFullSpan(true);
view.setLayoutParams(lp4);
vh = new ViewHolderRVProductItem(view);
break;
case Banner.ONE:
/**
* This banner occupies 1 column of the screen
* The height is set programmatically based on screen width
*
* Product image ratio is 32 x 15
*/
view = inflater.inflate(R.layout.item_banner_big, parent, false);
view.setOnClickListener(productClickListener);
StaggeredGridLayoutManager.LayoutParams lp = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
lp.setFullSpan(true);
view.setLayoutParams(lp);
view.setOnClickListener(productClickListener);
vh = new ViewHolderRVProductItem(view);
break;
case Banner.TWO:
/**
* This banner occupies 1 column of the screen
* The height is smaller than BANNER_ONE
* The height is set programmatically based on screen width
*/
view = inflater.inflate(R.layout.item_banner_big, parent, false);
view.setOnClickListener(productClickListener);
StaggeredGridLayoutManager.LayoutParams lp2 = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
lp2.setFullSpan(true);
view.setLayoutParams(lp2);
view.setOnClickListener(productClickListener);
vh = new ViewHolderRVProductItem(view);
break;
case Banner.THREE:
/**
* This banner occupies 3 column of the screen
* The height is set programmatically based on screen width
*/
view = inflater.inflate(R.layout.item_banner_long_rect, parent, false);
view.setOnClickListener(productClickListener);
vh = new ViewHolderRVProductItem(view);
break;
case Banner.FOUR:
/**
* This banner occupies 3 column of the screen
* The height is smaller than BANNER_THREE
* The height is set programmatically based on screen width
*/
view = inflater.inflate(R.layout.item_banner_long_rect, parent, false);
view.setOnClickListener(productClickListener);
vh = new ViewHolderRVProductItem(view);
break;
default: /** ProductItem.BANNER_FIVE **/
/**
* This banner occupies 2 column of the screen
* The height is set programmatically based on screen width
*/
view = inflater.inflate(R.layout.item_banner_recommended, parent, false);
view.setOnClickListener(productClickListener);
vh = new ViewHolderRVProductItem(view);
break;
}
/** Set image ratio **/
if (vh.productImage != null) {
final ViewHolderRVProductItem finalVh = vh;
vh.itemView.post(new Runnable() {
#Override
public void run() {
setImageRatio(finalVh.productImage, viewType, finalVh.productImage.getWidth());
}
});
}
return vh;
}
#Override
public void onBindViewHolder(final ViewHolderRVProductItem holder, final int position) {
if (holder == null) return;
final Context context = holder.itemView.getContext();
final ProductItem item = mItems.get(position);
holder.itemView.setTag(item);
final int bannerType = holder.getItemViewType();
final Banner banner = bannerType == Banner.ONE ? item.getBanner1() : (bannerType == Banner.FIVE ? item.getBanner5() : (bannerType == Banner.TWO ? item.getBanner2() : (bannerType == Banner.THREE ? item.getBanner3() : item.getBanner4())));
if (banner != null && holder.productImage != null) {
holder.productImage.post(new Runnable() {
#Override
public void run() {
float width = holder.productImage.getWidth();
float height = holder.productImage.getHeight();
Picasso.with(context)
.load(banner.getImageURL6())
.resize((int) width, (int) height)
.into(holder.productImage);
}
});
}
}
private void setImageRatio(ImageView imgview, int bannerType, int width) {
Context context = imgview.getContext();
switch (bannerType) {
case Banner.ONE:
/** Product image ratio is 32 x 15 **/
float height = (15f / 32f) * width;
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) imgview.getLayoutParams();
params.width = width;
params.height = (int) height;
imgview.setLayoutParams(params);
break;
case Banner.TWO:
/** Product image ratio is 11 x 3 **/
float height1 = (3f / 11f) * width;
LinearLayout.LayoutParams params1 = (LinearLayout.LayoutParams) imgview.getLayoutParams();
params1.width = width;
params1.height = (int) height1;
imgview.setLayoutParams(params1);
break;
case Banner.THREE:
/** Product image ratio: 27 x 40 **/
float height2 = (40f / 27f) * width;
RelativeLayout.LayoutParams params2 = (RelativeLayout.LayoutParams) imgview.getLayoutParams();
params2.width = (int) width;
params2.height = (int) height2;
imgview.setLayoutParams(params2);
break;
case Banner.FOUR:
int dip8 = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8f, context.getResources().getDisplayMetrics());
/** Product image ratio: 1 x 1 **/
int size = (int) width - dip8;
RelativeLayout.LayoutParams params3 = (RelativeLayout.LayoutParams) imgview.getLayoutParams();
params3.width = size;
params3.height = size;
params3.leftMargin = dip8;
params3.topMargin = dip8;
params3.rightMargin = dip8;
imgview.setLayoutParams(params3);
break;
case Banner.FIVE:
/** Product image ratio: 162 x 71 **/
float height3 = (71f / 162f) * width;
RelativeLayout.LayoutParams params4 = (RelativeLayout.LayoutParams) imgview.getLayoutParams();
params4.width = (int) width;
params4.height = (int) height3;
imgview.setLayoutParams(params4);
break;
}
}
}
The thing that the previous problem and this problem have done is changing the ImageView width & height programmatically. Why changing View's layout have impact in RecyclerView?
I've found an ultimate solution. Rather than using previous solution, i have found the culprit:
final ViewHolderRVProductItem finalVh = vh;
vh.itemView.post(new Runnable() {
#Override
public void run() {
setImageRatio(finalVh.productImage, viewType, finalVh.productImage.getWidth());
}
});
I think it's not recommended to modify ImageView's size using post inside an adapter. I'm now using AspectRatioImageView and it's working smoothly.
I am working on an application which has a main screen with a gridview layout.
As it stands currently, I am hardcoding in DP numbers for the height and width of the boxes, which I obviously do not want to do. How to I create code that will determine the users' screen size and match the boxes accordingly so that someone with a large phone like a note will view the same thing as someone on a droid mini? IE, when hardcoding to 500dp on each side, it looks like this:
But my goal is to make it look like this on every screen size:
Currently, this is the Java code I have:
public class ActivityAdapter extends BaseAdapter {
//Array of Icons that will be used as menu choices
public static int[] imageOptions = {
R.drawable.vacation_quota, //Position 0
R.drawable.revenue_deficit, //Position 1
//+ many more options...
};
private Context context;
//Constructor to pass context back to Main class
public ActivityAdapter(Context applicationContext) {
context = applicationContext;
}
//Number of elements to be displayed on the grid
#Override
public int getCount() {
return imageOptions.length;
}
#Override
public View getView(int position, View convertView, ViewGroup arg2) {
ImageView iv;
if(convertView != null){
iv = (ImageView) convertView;
} else {
iv = new ImageView(context);
//Here I have it hard coded to match a 480px width. Here is where I need to change it, just not sure how
iv.setLayoutParams(new GridView.LayoutParams(240, 240));
iv.setScaleType(ScaleType.CENTER_CROP); //Center the cropping
}
//Sets the image to correspond to its position within the array.
iv.setImageResource(imageOptions[position]);
return iv;
}
Any ideas? I think logically I want to figure out the screen dimensions and use them to make the image dimensions match, just not sure how. Research from other threads has not helped a great deal so hoping I can get a simpler answer here with code posting.
You should get the screen width and height. Then use these values to dynamically set height and width for each cell
Try this code-
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle state) {
setContentView(new ViewGroup(this) {
private RelativeLayout[] items = new RelativeLayout[9];
private int width, height, itemWidth, itemHeight;
{
Random r = new Random();
for (int i = 0; i < 9; i++) {
items[i] = new RelativeLayout(getContext());
float[] hsv = new float[] {360 * r.nextFloat(), .50f, .75f};
items[i].setBackgroundColor(Color.HSVToColor(hsv));
addView(items[i]);
// UPDATE ////////////////////////////////////
ImageView image = new ImageView(getContext());
switch (i) {
case 0: // top left
case 1: // top center
case 2: // top right
case 3: // center left
case 4: // center center
case 5: // center right
case 6: // bottom left
case 7: // bottom center
case 8: // bottom right
image.setImageResource(R.drawable.ic_launcher);
break;
}
image.setScaleType(ScaleType.FIT_XY);
image.setLayoutParams(new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT,
RelativeLayout.LayoutParams.MATCH_PARENT
));
items[i].addView(image);
//////////////////////////////////////////////
}
}
#Override
protected void onMeasure(int wMS, int hMS) {
width = MeasureSpec.getSize(wMS);
height = MeasureSpec.getSize(hMS);
itemWidth = width / 3;
itemHeight = height / 3;
wMS = MeasureSpec.makeMeasureSpec(itemWidth, MeasureSpec.EXACTLY);
hMS = MeasureSpec.makeMeasureSpec(itemHeight, MeasureSpec.EXACTLY);
measureChildren(wMS, hMS);
setMeasuredDimension(width, height);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
for (int i = 0; i < 9; i++) {
l = itemWidth * (i % 3);
t = itemHeight * (i / 3);
r = l + itemWidth;
b = t + itemHeight;
items[i].layout(l, t, r, b);
}
}
});
super.onCreate(state);
}
}
Output-
Edit-
For creating scrollable grid view see this http://www.androidhive.info/2012/02/android-gridview-layout-tutorial/
I ended up not able to use some of the recommendations here and had to use a deprecated method to retain my app structure. The code specifically that was added to mine was:
iv = new ImageView(context);
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
float width2 = display.getWidth();
int length = (int) (width2/2);
iv.setLayoutParams(new GridView.LayoutParams(length, length));
With this, the height and width would crop to the right size depending on the size of the screen.
I want to show 3x3 sized gridview. I want to set the height and width based on device size. I am taking reference from this link.
MainActivity-
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GridView gridview = (GridView) findViewById(R.id.gridview);
gridview.setAdapter(new ImageAdapter(this));
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
activity_main-
<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/gridview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:columnWidth="90dp"
android:numColumns="auto_fit"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp"
android:stretchMode="columnWidth"
android:gravity="center"
/>
Edit-
Like first getting screen height and width then each item height and width 1/3 of the value of screen height and width I am getting.
Do not use screen size, in a multi-windows context this method is invalid.
If your grid is a 3x3 items size fixed, so use custom layout ViewGroup like this: (and set RelativeLayout items content)
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle state) {
setContentView(new ViewGroup(this) {
private RelativeLayout[] items = new RelativeLayout[9];
private int width, height, itemWidth, itemHeight;
{
Random r = new Random();
for (int i = 0; i < 9; i++) {
items[i] = new RelativeLayout(getContext());
float[] hsv = new float[] {360 * r.nextFloat(), .50f, .75f};
items[i].setBackgroundColor(Color.HSVToColor(hsv));
addView(items[i]);
// UPDATE ////////////////////////////////////
ImageView image = new ImageView(getContext());
switch (i) {
case 0: // top left
case 1: // top center
case 2: // top right
case 3: // center left
case 4: // center center
case 5: // center right
case 6: // bottom left
case 7: // bottom center
case 8: // bottom right
image.setImageResource(R.drawable.ic_launcher);
break;
}
image.setScaleType(ScaleType.FIT_XY);
image.setLayoutParams(new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT,
RelativeLayout.LayoutParams.MATCH_PARENT
));
items[i].addView(image);
//////////////////////////////////////////////
}
}
#Override
protected void onMeasure(int wMS, int hMS) {
width = MeasureSpec.getSize(wMS);
height = MeasureSpec.getSize(hMS);
itemWidth = width / 3;
itemHeight = height / 3;
wMS = MeasureSpec.makeMeasureSpec(itemWidth, MeasureSpec.EXACTLY);
hMS = MeasureSpec.makeMeasureSpec(itemHeight, MeasureSpec.EXACTLY);
measureChildren(wMS, hMS);
setMeasuredDimension(width, height);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
for (int i = 0; i < 9; i++) {
l = itemWidth * (i % 3);
t = itemHeight * (i / 3);
r = l + itemWidth;
b = t + itemHeight;
items[i].layout(l, t, r, b);
}
}
});
super.onCreate(state);
}
}
EDIT : see my update in code, you have simply to add your images to the items containers. With this method, no XML layout file needed because you manage content and size yourself.
Result :
EDIT : the minimalist way:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle state) {
setContentView(new ViewGroup(this) {
private static final int SIZE_X = 3;
private static final int SIZE_Y = 3;
private ImageView[] items = new ImageView[SIZE_X * SIZE_Y];
private int itemWidth, itemHeight;
{
setBackgroundColor(Color.DKGRAY);
for (int i = 0; i < items.length; i++) {
items[i] = new ImageView(getContext());
items[i].setScaleType(ScaleType.CENTER);
items[i].setImageResource(R.drawable.ic_launcher);
addView(items[i]);
}
}
#Override
protected void onMeasure(int wMS, int hMS) {
int width = MeasureSpec.getSize(wMS);
int height = MeasureSpec.getSize(hMS);
itemWidth = width / SIZE_X;
itemHeight = height / SIZE_Y;
wMS = MeasureSpec.makeMeasureSpec(itemWidth, MeasureSpec.EXACTLY);
hMS = MeasureSpec.makeMeasureSpec(itemHeight, MeasureSpec.EXACTLY);
measureChildren(wMS, hMS);
setMeasuredDimension(width, height);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
for (int i = 0; i < items.length; i++) {
l = itemWidth * (i % SIZE_X);
t = itemHeight * (i / SIZE_X);
r = l + itemWidth;
b = t + itemHeight;
items[i].layout(l, t, r, b);
}
}
});
super.onCreate(state);
}
}
Result :
# Kanwaljit Singh:
In MainActivity items creation loop:
final int id = i;
items[i].setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(getContext(), NextActivity.class).putExtra("id", id));
}
});
In NextActivity:
int id = getIntent().getIntExtra("id", -1);
You can get the screen dimensions like:
final DisplayMetrics displayMetrics=getResources().getDisplayMetrics();
final float screenWidthInDp=displayMetrics.widthPixels;
Log.WTF("ScreenWidth", "width: "+screenWidthInDp+", menuWidth: "+screenWidthInDp/3);
And for the gridview, I would suggest you to take a look at this awesome library called Staggered Grid View. And their sample here.
I use the following approach when I have to resize my Activitys, I assume the same is valid for your case:
// I'm storing the size of the window in the display var, so I can then play around
final Display display = getWindowManager().getDefaultDisplay();
final Point size = new Point();
display.getSize(size);
// In your case, you'll probably need something like this:
GridView gv = (GridView) findViewById(R.id.gridview);
gv.setWidth((int) size.x * 0.75); // Whis would resize the grid width to the 75%
gv.setHeight((int) size.y * 0.5); // Same with the height, but to the 50%
I have implemented and activity (called HomeScreenActivity) that consists of two fragments. One of them displays a list of items, and the other displays the details of the selected item. The details fragment (ResumeFragment in my code) consists of a series of components, which can be configured in height and width by the user by specifying it as a number of cells in a configurations file. These components are added to a custom layout called ComponentsLayout.
When opening the HomeScreenActivity i display each fragment in the onCreate method, and they are shown as intended.
But when i click and item in the items list fragment, and i replace the resumeFragment with a new instance of the same class, nothing is displayed.
I have spend a lot of time debugging and i see that the resumeFragment, does fill out the height and width it is given, but the componentsLayout only has a height of 1. This i have found out is because the height and width of the components contained in the componentsLayout are not getting set, even though i set their layoutParams in the componentsLayout onMeasure method.
Below is the code of the HomeScreenActivity, the ResumeFragment and the ComponentsLayout:
public class HomeScreenActivity extends FragmentActivity implements OnItemSelectedListener {
.
.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.home_screen);
.
.
//Check if device is in landscape orientation
if(width > height && isTablet) {
//The patient context fragment must maintain the same width as when in portrait orientation.
findViewById(R.id.patient_resume_fragment_container).setLayoutParams(new LinearLayout.LayoutParams(height, height));
findViewById(R.id.screen_pager).setLayoutParams(new LinearLayout.LayoutParams(width-height, height));
fragmentManager = getSupportFragmentManager();
patientResumeFragment = new ResumeFragment();
testFragment = new NysomTestFragment();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.patient_resume_fragment_container, patientResumeFragment);
fragmentTransaction.commit();
}
}
.
.
#Override
public void onItemSelected(Item item) {
itemResumeFragment.getView().findViewById(R.id.componentsContainer);
itemResumeFragment = new ResumeFragment(item);
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.item_resume_fragment_container, itemResumeFragment);
fragmentTransaction.commit();
}
The ResumeFragment
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View fragmentView = inflater.inflate(R.layout.resume_fragment,container, false);
ComponentsLayout componentsContainer = (ComponentsLayout) fragmentView.findViewById(R.id.componentsContainer);
placeComponents(componentsContainer);
return fragmentView;
}
private void placeComponents(ComponentsLayout layout) {
List<ComponentConfig> configs = new ArrayList<ComponentConfig>(testMobile.getModel().getComponentConfiguration());
int viewId = 1;
for (ComponentConfig currConfig : configs) {
ComponentsLayout.LayoutParams params = new ComponentsLayout.LayoutParams(0, 0);
params.setWidthInCells(currConfig.getWidth());
params.setHeightInCells(currConfig.getHeight());
if (viewId == 1) {
params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
} else {
if (currConfig.getPositionX() > 0) {
// looking for rightOf viewId
params.addRule(RelativeLayout.RIGHT_OF, getRightOfComponentId(configs, currConfig, viewId - 1));
}
if (currConfig.getPositionY() > 0) {
// looking for below viewId
params.addRule(RelativeLayout.BELOW, getBelowComponentId(configs, currConfig, viewId - 1));
}
}
try {
// this code will be changed in story 9
View view = currConfig.getClassType().newInstance().getView(getActivity());
view.setId(viewId);
view.setBackgroundColor(colors[(viewId - 1) % 6]);
layout.addView(view, params);
} catch (Exception e) {
// we should never get to this point as configuration is validated
Log.e(TAG, "getView: unable to create component for position " + viewId, e);
throw new RuntimeException(e);
}
viewId++;
}
}
And the ComponentLayout
public class ComponentsLayout extends RelativeLayout {
public ComponentsLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int horizontalCellsNum = getResources().getInteger(R.integer.resume_horizontal_cells_num);
int cellHeight = (int) (getResources().getDimension(R.dimen.resume_cell_height));
int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
LayoutParams params = (LayoutParams) child.getLayoutParams();
params.width = parentWidth * params.getWidthInCells() / horizontalCellsNum;
params.height = cellHeight * params.getHeightInCells();
child.setLayoutParams(params);
}
}
And once again, this works when called from the HomeScreenActivity onCreate method, but not when done from the onItemSelected method.
Can anyone help??
I have created a work around by adding all layout params to the components before onMeasure is called on the componentLayout. It was not the solution i was looking for, but it was quite simple, which is possibly why i overlooked it.