Android: how can I rotate image and set it filling fragment? - java

I have a fragment that displays some images on 30% of the screen. In case when image.height is bigger than image.width, I wanted to rotate the image 90 degrees. However, after that operation, the image does not fully fill the fragment - "new" width after rotation matches previous height, so the image occupies only some part in the middle of the fragment. How can I make it a matching fragment? What I'm doing wrong or missing?
This is how it looks like without rotation:
This is after rotation:
And that's what I want to have:
Here is the code:
#Override
public void onViewCreated(#NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
setImageFittedToDisplay(view);
}
public void setImageFittedToDisplay(View view) {
int height = getDisplayMetrics().heightPixels;
ViewGroup.LayoutParams params = view.getLayoutParams();
params.height = ((Double) (height * 0.3)).intValue();
view.setLayoutParams(params);
ImageView image = view.findViewById(R.id.picture);
image.setDrawingCacheEnabled(true);
int w = image.getDrawable().getIntrinsicWidth();
int h = image.getDrawable().getIntrinsicHeight();
if(h > w) {
image.setRotation(90f);
}
ViewGroup.LayoutParams imageParams = image.getLayoutParams();
imageParams.height = ActionBar.LayoutParams.WRAP_CONTENT;
imageParams.width = ActionBar.LayoutParams.WRAP_CONTENT;
image.setLayoutParams(imageParams);
}
and here is .xml of the fragment:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/APOD_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ImageView
android:id="#+id/picture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/cool_pic"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="#+id/separator"
android:layout_width="match_parent"
android:layout_height="10dp"
android:background="#color/colorSeparator"
app:layout_constraintBottom_toBottomOf="#+id/picture"
app:layout_constraintTop_toBottomOf="#+id/picture" />
</androidx.constraintlayout.widget.ConstraintLayout>

Related

How to resize RecyclerView when Material BottomSheet is Expanded?

I have a layout where i have a bottom sheet which could be expanded, then from that bottomsheet i can click some items which then will be added to my RecyclerView, the issue is that when the bottomsheet is expanded i'm unable to see the last added items as the recyclerView goes behind the bottomSheet.
So i would do something like the bottomSheet pushes to top the recyclerView (or that the recyclerView is resized)
The issue is that i was trying to do the resize in onSlide but it doesn't work as expected...
Here is my Layout:
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="2dp"
app:layout_anchorGravity="top"
android:layout_marginBottom="60dp"
app:layout_anchor="#+id/bottomSheet"
android:padding="2dp"
android:scrollbars="vertical"
tools:listitem="#layout/recyclerview_pterm" />
<include layout="#layout/bottom_sheet_pterm" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
And my BottomSheetBehavior callback:
bottomSheet.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
#Override
public void onStateChanged(#NonNull View bottomSheet, int newState) {
if (newState == BottomSheetBehavior.STATE_EXPANDED) {
mRecyclerViewTOP.scrollToPosition(dummyDataItems.size() - 1);
}
}
#Override
public void onSlide(#NonNull View bottomSheet, float slideOffset) {
int padding = bottomSheet.getHeight();
ViewGroup.LayoutParams params= mRecyclerViewTOP.getLayoutParams();
params.height = params.height - padding;
mRecyclerViewTOP.setLayoutParams(params);
}
});
So how could i make the recyclerView shows ever the last inserted item even when bottomSheet is expanded?

Android: How to programatically change the width of an ImageView without resizing its image?

I am trying to programatically change the width of an ImageView without resizing the image. The ImageView originally shows the entire image, but when the width of the image is decreased, a portion of the image should be cut off, like this:
However, when my code reduces the width of the ImageView from 350dp to 200dp, the image is automatically resized instead:
How do I ensure that the ImageView does not resize the image when I decrease its width? Below is my code:
activity_main.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" >
<ImageView
android:id="#+id/photo_1_preview"
android:layout_width="350dp"
android:layout_height="350dp"
android:adjustViewBounds="false"
android:background="#drawable/android"/>
</LinearLayout>
MainActivity.java:
package com.example.changingimageviewwidth;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ImageView;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Reduce the width of the image preview box
ImageView imagePreviewBox = findViewById(R.id.photo_1_preview);
imagePreviewBox.getLayoutParams().width = 250;
}
}
Use android:scaleType="matrix" for the ImageView and put the desired image in android:src.
NOTE: In this case, I set the LinearLayout to be 400x400 because the image size is 400x400 px and wrap the ImageView inside of a LinearLayout just for clarity.
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#333333"
android:gravity="center"
android:orientation="vertical">
<LinearLayout
android:layout_height="400px"
android:layout_width="400px"
android:orientation="vertical"
android:background="#0000FF">
<ImageView
android:layout_height="match_parent"
android:layout_width="match_parent"
android:src="#drawable/android"
android:scaleType="matrix"
android:id="#+id/iv"/>
</LinearLayout>
</LinearLayout>
MainActivity.java
public class MainActivity extends Activity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ImageView iv = findViewById(R.id.iv);
ViewGroup.LayoutParams params = iv.getLayoutParams();
params.width = 200; //200 pixels.
//Not necessary in my test. You may need to call the following
//method if you set the params outside of onCreate(), onCreateView().
//iv.requestLayout();
}
}
Output:
Set the scale type to CENTER_CROP. That will center the image in the view, and crop out anything that doesn't fit.
To get your desired behavior, simply set android:scaleType="fitStart" to your ImageView in xml. It will not change the aspect ratio of the src, but aligns it to the start of the ImageView, just as you mentioned.
The problem you're facing is because the drawable is set as a background of ImageView instead of being set as a source
After you fix that, the right scaleType to choose for your use-case is fitStart which will maintain the original aspect ratio for the bitmap and align it to the top-left of the ImageView
Please use the updated layout file -
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ImageView
android:id="#+id/photo_1_preview"
android:layout_width="350dp"
android:layout_height="350dp"
android:adjustViewBounds="false"
android:scaleType="fitStart"
android:src="#drawable/android"/>
</LinearLayout>
Try with the following code.
//activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/darker_gray"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="#+id/image_view"
android:layout_width="300dp"
android:layout_height="300dp"
android:scaleType="fitCenter"
android:src="#drawable/dumy" />
</LinearLayout>
//MainActivity.java
public class MainActivity extends AppCompatActivity {
private ImageView imageView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = findViewById(R.id.image_view);
imageView.getLayoutParams().width = dpToPixels(150);
imageView.requestLayout();
imageView.invalidate();
}
private int dpToPixels(int size) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, size, getResources().getDisplayMetrics());
}
}

Problem with inflating xml-Layout on custom layout class

I have a custom ConstraintLayout class (Card.java) which overrides the onDraw() method to draw a hexagon in his background. On the foreground i try to have three TextViews to display three numbers.
For this I inflate a card.xml in the constructor of Card. The TextViews are displayed, but not at the right position. They should match the width and height of the Card and then position itself to the top-left and top-right corner and one to the bottom of the Card. But they do something like shrink itself and go to the top-left corner.
I have tried to change the root element of card.xml to "merge" instead of "...ConstraintLayout" but this doesn't change anything.
I also tried to use Guidelines to position the TextViews relative to its width. I try to prevent the use of fixed margins, so the Text is always at the right place, also when the size of the Card changes.
Card.java:
public class Card extends ConstraintLayout {
private int mSize;
private Path mHexagon;
private Paint mPaintHexagon;
private TextView mT1, mT2, mT3;
public Card(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
inflate(context, R.layout.card, this);
// Numbers
mT1 = findViewById(R.id.num1);
mT2 = findViewById(R.id.num2);
mT3 = findViewById(R.id.num3);
// Hexagon
mSize = Field.getHexSize(); // Size is used to calculate the
setPath();
mPaintHexagon = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintHexagon.setColor(0x50888888);
mPaintHexagon.setStyle(Paint.Style.FILL);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawPath(mHexagon, mPaintHexagon);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = 2 * mSize;
int height = (int) (Math.sqrt(3) * mSize);
Log.d(TAG, "Measure w:" + width + " h:" + height);
setMeasuredDimension(width, height);
}
}
card.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
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"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/num2"
android:textAppearance="#style/TextAppearance.AppCompat.Large"
android:text="2"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="8dp"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="8dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/num1"
android:textAppearance="#style/TextAppearance.AppCompat.Large"
android:text="1"
app:layout_constraintStart_toEndOf="#+id/num2"
app:layout_constraintEnd_toStartOf="#+id/num3"
app:layout_constraintBottom_toBottomOf="parent"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/num3"
android:textAppearance="#style/TextAppearance.AppCompat.Large"
android:text="3"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginEnd="8dp"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="8dp"/>
</android.support.constraint.ConstraintLayout>
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:background="#color/colorAccentDark"
android:padding="5dp">
<de.portugall.markus.takeiteasy.Card
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:id="#+id/card"/>
</android.support.constraint.ConstraintLayout>
Screenshot Card in Layout-Debug mode
'onMeasure()` has some rules that you are not strictly following. I have seen these rules broken with impunity, but I think that you are being caught, but we will push on.
In onMeasure() you are setting the height and width of the custom layout but ConstraintLayout still understands the layout as wrap_content. You will need to set the layout params to the new height and width. Add the following code to the end of onMeasure():
// Although we have measured the layout, we need to tell ConstraintLayout in the
// LayoutParams that the size is not longer "wrap_content".
ViewGroup.LayoutParams lp = getLayoutParams();
lp.width = width;
lp.height = height;
setLayoutParams(lp);
The second issue that you have is that you are adding a ConstraintLayout (card.xml) to a ConstraintLayout (your custom layout), but you are not setting the constraints. In the constructor for Card.java, add the following to set the constraints:
ConstraintLayout layout = (ConstraintLayout) inflate(context, R.layout.card, this);
// We have added R.layout.card to a ConstraintLayout (this custom layout), so we need
// to make sure that it is constrained properly.
ConstraintSet cs = new ConstraintSet();
cs.clone(layout);
cs.connect(R.id.layout, ConstraintSet.START, ConstraintSet.PARENT_ID, ConstraintSet.START);
cs.connect(R.id.layout, ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.TOP);
cs.connect(R.id.layout, ConstraintSet.END, ConstraintSet.PARENT_ID, ConstraintSet.END);
cs.connect(R.id.layout, ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM);
cs.applyTo(layout);
You will need to change the height and width of the layout in card.xml to 0dp. match_parent is never appropriate in ConstraintLayout.
This is a pictorial description of what is happening:
On a related note, you should consider using the merge facility to avoid nested ConstraintLayouts as other have mentioned.

Android making an scrolled two independent listview in activity

I am working in Android Studio in a new app and I want to create a layout with two independent scrolled listview (each listview scrolling in independent way) in the same activity. I cannot obtain the target that I want. Could you give me some advice?
I am not sure about efficient way but I worked in following way.
First, I have created two dynamic ListView and put in into one activity.
It will calculate the height dynamically rather than match_parent.
Here is the code:
public void setListViewDynamicHeight(ListView listView) {
ListAdapter adapter = listView.getAdapter();
if (adapter == null) {
return;
}
int height = 0;
int desiredWidth = View.MeasureSpec.makeMeasureSpec(listView.getWidth(), View.MeasureSpec.UNSPECIFIED);
for (int i = 0; i < adapter.getCount(); i++) {
View listItem = adapter.getView(i, null, listView);
listItem.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED);
height += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams layoutParams = listView.getLayoutParams();
layoutParams.height = height + (listView.getDividerHeight() * (adapter.getCount() - 1));
listView.setLayoutParams(layoutParams);
listView.requestLayout();
}
You can build it in your layout xml like this:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v4.widget.NestedScrollView
android:id="#+id/nested_scroll_view_1"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Hallo!" />
<!--Other views inside NestedScrollView-->
</android.support.v4.widget.NestedScrollView>
<android.support.v4.widget.NestedScrollView
android:id="#+id/nested_scroll_view_2"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Hallo!" />
<!--Other views inside NestedScrollView-->
</android.support.v4.widget.NestedScrollView>
</LinearLayout>

Image is not loading

I was wondering why the image here is not loading at all. The XML file does not show the image, it does however show the TextView and the Button.
Please help.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:id="#+id/textView2"
android:layout_width="177dp"
android:layout_height="wrap_content"
android:text="Middle Right Pop Up" />
<Button
android:id="#+id/button2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button" />
<ImageView
android:id="#+id/small_circle"
android:layout_width="180dp"
android:layout_height="wrap_content"
app:srcCompat="#drawable/small_compass" />
</LinearLayout>
,
public class PopUpMiddleRight extends Activity{
ImageView compass;
private float currentDegree = 0f;
private static SensorManager sensorService;
private Sensor sensor;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pop_up_middle_right);
WindowManager.LayoutParams windowManager =
getWindow().getAttributes();
windowManager.dimAmount = 0.75f;
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
int width = dm.widthPixels;
int height = dm.heightPixels;
getWindow().setLayout((int)(width * .8), (int)(height * .6));
}
}
I am trying to make a pop up window so it would look something like this:
Also Please note that I am referencing the image in another place in my code, so it can read the image.
Replace
app:srcCompat="#drawable/small_compass" to android:src="#drawable/small_compass" instead

Categories

Resources