prevent gridView from expanding to fit landscape width - java

I have a gridView with 4 columns of imgs. When phone is turned to landscape layout, grids of the gridView expand to fill the width, creating white spaces in between the img although the img stay at desired width. Is there a way to keep the grid view from filling width of screen when in landscape layout ?

I have 2 methods to do that:
1) Create layout for each orientation:
res/layout/....
res/layout-land/....
2) Only one layout for both vertical and horizontal orientation:
set up GridView with: android:numColumns="4"
your custom view item, always set android:layout_width="match_parent"
with the second method, you may encount problem with high of item. Just create your custom View and override onMeasure.
For example: I need a LinearLayout for my item and the keep my ratio height/width = 4.5/4, so I do the following custom:
public class MyLinearLayout extends LinearLayout {
//..... constructor methods
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int scaleHeight =(int)( widthMeasureSpec/4*4.5);
super.onMeasure(widthMeasureSpec, scaleHeight);
}
}

Related

converting CardView from RecyclerView to a Bitmap

I have a CardView (with multiple items like imageView, textView, Buttons) in a RecyclerView. I want to get bitmap from this cardview. I tried a simple method of converting cardView into bitmap (convert a cardview to bitmap) but its not working properly. I only got the raw view of the card just like in xml without any updated items from a firebaseserver.
CardView extend view, so you probably can convert it as any other view,
try to pass the CardView into that function:
public static Bitmap getBitmapFromView(View view) {
//Define a bitmap with the same size as the view
Bitmap returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),Bitmap.Config.ARGB_8888);
//Bind a canvas to it
Canvas canvas = new Canvas(returnedBitmap);
//Get the view's background
Drawable bgDrawable =view.getBackground();
if (bgDrawable!=null)
//has background drawable, then draw it on the canvas
bgDrawable.draw(canvas);
else
//does not have background drawable, then draw white background on the canvas
canvas.drawColor(Color.WHITE);
// draw the view on the canvas
view.draw(canvas);
//return the bitmap
return returnedBitmap;
}
you are probably taking the screenshot of view before it is fully inflated. Try adding a 2 second delay or implement this on layout listener of the card view

Storing assigned ViewGroup.MarginLayoutParams and modifying them at arbitrary moments

I need to modify custom View's ViewGroup.MarginLayoutParams depending on some inner state of the View.
The task looks like this:
Set some of the ViewGroup.MarginLayoutParams during View's initialization at the same time saving them to keep track of what was set via View's layout attributes (layout_marginTop, etc).
At the desired moments in the future, change ViewGroup.MarginLayoutParams using either stored values or some other ones.
Hence, I have 2 questions:
What is the right place to save ViewGroup.MarginLayoutParams set via the layout attributes?
Can't do it in the View's constructor, since the parent ViewGroup hasn't yet assigned it. Is onAttachedToWindow() the correct place for that?
Is onMeasure() the correct place for adjusting ViewGroup.MarginLayoutParams as needed?
Something like this:
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams)getLayoutParams();
params.topMargin = ...;
setLayoutParams(params);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
Since in the code above we're calling setLayoutParams() in onMeasure() (when the current layout pass in progress), would it cause the second layout pass?
You can just keep a reference to the ViewGroup that you're working with, and call getLayoutParams as needed. You'll need to make the params variable a more specific instance of ViewGroup- You could instantiate it as
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) view.getLayoutParams();
Then, you can just call your choice of
params.setMarginStart(int);
params.setMarginEnd(int);
params.setMargins(int, int, int, int);
to set the margins. Note that you do NOT need to call setLayoutParams() at all to have the changes apply. The params variable and view.getLayoutParams() reference the same object, so any changes you make to one will apply to the other.
A full code example could look like the following:
public final class MyActivity extends AppCompatActivity {
RelativeLayout parent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
parent = (RelativeLayout) findViewById(R.id.parent);
}
private void setParentMargin(int left, int top, int right, int bottom) {
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) parent.getLayoutParams();
params.setMargins(left, top, right, bottom);
params.setMarginStart(left);
params.setMarginEnd(right);
}
}
As long as you call that method after onCreate, you should be fine.
The answer to your second question depends on what event is triggering the change in margin. If it's whenever the activity gets recreated, you could do it in onResume (because that's guaranteed to happen after onCreate). You could also call it from an onClickListener, or from an interface callback. So, you do not necessarily have to set the margins in onMeasure.

How do I affect another view's property when ImageView is pressed?

I have an ImageView inside a LinearLayout view. I want to change the color of the LinearLayout view while the ImageView is pressed.
I know I can swap out the ImageView image when the state changes through drawables, but I cannot seem to find the ideal way to affect another view in the layout while isPressed is true on this specific image view.
Ultimately, I am trying to create a bottom ActionBar and simulate the regular ActionBar highlight box (that is, when you press a menu item in the ActionBar you get the highlight box). Right now I have the ImageView a LinearLayout with a small (8dp) padding on the top and bottom. I can replace the image in the ImageView with one that has a 50% white background, but I cannot do it this way if I want to keep the images device density independent. Instead, I'd like to have a square layout the button exists in that I would change the color of as needed.
Ideas?
"I have an ImageView inside a LinearLayout view. I want to change the color of the LinearLayout view while the ImageView is pressed."
for this :
you define your ImageView in XML as clickable android:clickable="true"
you affect an OnClickListener to this ImageView in your Activity onCreat() :
ImageView yourImage = (ImageView) findViewById(R.id.your_image);
yourImage.setClickable(true); // if you want to define it here
yourImage.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
findViewById(R.id.your_linear_layout).setBackgroundColor(your_color);
}
});
Else if you want to change the color only when it is clicked and restore the old color after the click, you can implement OnTouchListener :
yourImage.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(final View v, MotionEvent event) {
int action = event.getAction() & MotionEvent.ACTION_MASK;
if (action == MotionEvent.ACTION_DOWN) {
// when the click begins
findViewById(R.id.your_linear_layout).setBackgroundColor(your_click_color);
return true;
} else {
// when the click finishs
findViewById(R.id.your_linear_layout).setBackgroundColor(your_init_color);
return true;
}
return false;
}
});
I hope I helped...

How do I have an ActionBar icon/logo that overlaps the content as well?

I'm currently making one of my very first applications. I'm using ActionBarSherlock.
I would like to make my logo overlap the actionbar (scrollview).
Currently I have main_activity.xml. In MainActivity.java I use setContentView to view main_activity.xml. After that I use getSupportActionBar() for ActionBarSherlock. I've tried things out using RelativeLayout  (http://www.mkyong.com/android/android-relativelayout-example/). That didn't really work because there are multiple layouts.
So I've tried some things right and left, but it always ends up infront or behind the actionbar, or stops just before reaching the content. It's because of two different layouts, that's what I know. But how can I going to solve this? Is it possible? Thanks in advance!
What I want:
http://f.cl.ly/items/3N0w243N1t2Q3i1H1f1k/Untitled-1.png
You can either:
A. Split your image in two
Have the top part as the ActionBar logo, then show the bottom part over your content.
B. Use a single image
You'll need a layout file that contains just your logo (you'll probably want something like an ImageView inside a LinearLayout so you can easily set the correct margins).
Then after calling setContentView for your activity, add your logo view with:
ViewGroup decorViewGroup = (ViewGroup) getWindow().getDecorView();
decorViewGroup.addView(logoView);
Using a layout file
Example layout file (logo_view.xml):
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/logo_image"
android:scaleType="center"
android:layout_marginLeft="10dip"
/>
</LinearLayout>
Inflate the layout file:
LayoutInflater inflater = LayoutInflater.from(this);
View logoView = inflater.inflate(R.layout.logo_view, null, false);
Although the original answer works on some devices, on others the image sits under the status bar. I resolved this by getting the location of the top ActionBar and comparing it to the location of the top of the logo image and then just adding some top padding, as follows:
// Inflate logo layout
LayoutInflater inflater = LayoutInflater.from(this);
final View logoView = inflater.inflate(R.layout.menu_logo, null);
// Add logo to view
ViewGroup viewGroup = (ViewGroup) getWindow().getDecorView();
viewGroup.addView(logoView);
// Adjust the logo position
int resId = getResources().getIdentifier("action_bar_container", "id", "android");
final View actionBarView = viewGroup.findViewById(resId);
if (actionBarView != null) {
actionBarView.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
public void onGlobalLayout() {
// Remove the listener
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
actionBarView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
actionBarView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
// Measure views
int[] location = new int[2];
actionBarView.getLocationOnScreen(location);
int[] logoLocation = new int[2];
logoView.getLocationOnScreen(logoLocation);
// Add top padding if necessary
if (location[1] > logoLocation[1]) {
logoView.setPadding(0, location[1] - logoLocation[1], 0, 0);
}
}
}
);
}
This worked on a wide range of devices (phones, big/small tablets - inc Kindle Fire HDX) running Android versions 4.0 up to 4.4.4 as well as Android L preview.

Android ImageView - Fill width and Resize to Maintain Aspect Ratio

I have a row View that I am using in a ListView.
This RowView consists of an ImageView on the left and a TextView on the right in a horizontal LinearLayout where the image is given 40% of the space and the text the remaining 60%.
I want the layout to handle the resizing of the image in the ImageView in the following manner:
Stretch the image horizontally so that it fills up given 40% of the LinearLayout
Resize the ImageView vertically to maintain the original aspect ratio
This is my approach to the layouts:
protected class RowView extends LinearLayout {
public ImageView iv = null;
public TextView tv = null;
private LinearLayout.LayoutParams ivlp = null;
private LinearLayout.LayoutParams tvlp = null;
public RowView(Context ct) {
super(ct);
setOrientation(LinearLayout.HORIZONTAL);
// Create the views
iv = new ImageView(ct);
ivlp = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, 0.4f);
iv.setLayoutParams(ivlp);
iv.setAdjustViewBounds(true);
iv.setScaleType(ScaleType.FIT_XY);
tv = new TextView(ct);
tvlp = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, 0.4f);
tv.setLayoutParams(tvlp);
tv.setGravity(Gravity.CENTER_VERTICAL | Gravity.RIGHT);
// Add the views
addView(iv);
addView(tv);
}
}
The result I am getting is something like this:
From what I understand:
The MATCH_PARENT is correctly forcing the image to horizontally stretch to fill the 40% space
The ImageView.setAdjustViewBounds(true) is supposed to allow any resizing of the ImageView that is necessary which is what I want. The problem is none of the ImageView.ScaleType's seem to do what I want
ImageView.ScaleType(ScaleType.FIT_XY) is not what I want because it doesn't maintain the aspect ratio. But all the others that do, don't seem to stretch the height of the ImageView (which is making ImageView.setAdjustViewBounds(true) pretty much useless).
What am I doing wrong? It seems wrong that something this simple could be so difficult?
Or do I actually have to go to the effort of extending an ImageView and Overriding onMeasure to force the resizing and aspect ratio?
Or is there a clever trick with Matrix to get the job done?
I believe this is what you are looking for:
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/myImage"
android:scaleType="fitCenter"
android:adjustViewBounds="true" />
Remove the scale type completely. Also, I think you might have misunderstood what setAdjustViewBounds does. If an image is scaled, the bitmap in the ImageView is scaled, but not the ImageView. Setting setAdjustViewBounds to true will assure that the ImageView's bounds will always match the drawn bitmap's bounds.

Categories