#java #android
Вопрос:
Я создаю приложение, в котором пользователь нажимает на a Button
, чтобы ввести выбранное изображение в an ImageView
. Изначально изображение правильно обрезано на 50% справа, как показано ниже:
Затем пользователь может перетащить ползунок влево, чтобы показать меньше изображения, или вправо, чтобы показать больше изображения. Однако, когда пользователь перемещает ползунок, приложение аварийно завершает работу, возвращая следующую ошибку нулевого объекта в строке кода, в которой я установил ImageView
фон для недавно обрезанного изображения на основе хода выполнения ползунка ( singlePreviewBox.setBackground(mClipDrawable);
).
java.lang.Исключение NullPointerException: Попытка вызвать виртуальный метод в android.graphics.drawable.Drawable.getOpacity()’ по нулевой ссылке на объект в android.graphics.drawable.ClipDrawable.getOpacity(ClipDrawable.java:159) в android.view.View.computeOpaqueFlags(View.java:15698) в android.view.View.setBackgroundDrawable(View.java:20502) в android.view.View.setBackground(View.java:20395) в com.пример.изменение ширины изображения.Основная активность$1.onProgressChanged(основная активность.java:49)
Это кажется странным, учитывая, что код, выполняющий начальную обрезку 50% справа, работает, и я использовал тот же код в своем прослушивателе слайдера.
Ниже приведен мой код:
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@ id/transition_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center_horizontal">
<Button
android:id="@ id/photo_input_1"
android:onClick="chooseFile"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:fontFamily="sans-serif"
android:text="No Photo"
android:textAllCaps="false"
android:textSize="16sp"
android:background="#f3f3f3"
android:elevation="4dp"
android:layout_margin="4dp"
android:minHeight="40dp"/>
<SeekBar
android:id="@ id/image_reveal_slider"
style="@style/Widget.AppCompat.SeekBar.Discrete"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="10"
android:progress="5" />
<ImageView
android:id="@ id/image_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxHeight="370dp"
android:adjustViewBounds="true"/>
</LinearLayout>
MainActivity.java:
package com.example.changingimageviewwidth;
import androidx.appcompat.app.AppCompatActivity;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ClipDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.Toast;
import java.io.InputStream;
public class MainActivity extends Activity
{
// Request code used when reading in a file
private Integer READ_IN_FILE = 0;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SeekBar imageRevealSlider = (SeekBar) findViewById(R.id.image_reveal_slider);
// perform seek bar change listener event used for getting the progress value
imageRevealSlider.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
int progressChangedValue = 0;
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
progressChangedValue = progress;
ImageView singlePreviewBox = findViewById(R.id.image_container);
singlePreviewBox.invalidate();
ClipDrawable mClipDrawable = new ClipDrawable(singlePreviewBox.getDrawable(), 11,
ClipDrawable.HORIZONTAL);
mClipDrawable.setLevel((progress / 10) * 10000);
singlePreviewBox.setImageResource(0);
singlePreviewBox.setBackground(mClipDrawable);
}
public void onStartTrackingTouch(SeekBar seekBar) {
// TODO Auto-generated method stub
}
public void onStopTrackingTouch(SeekBar seekBar) {
Toast.makeText(MainActivity.this, "Seek bar progress is :" progressChangedValue,
Toast.LENGTH_SHORT).show();
}
});
}
public void chooseFile(View v) {
// Specify that only photos are allowed as inputs (.jpg, .png).
Intent photoInputSpecs = new Intent(Intent.ACTION_GET_CONTENT);
photoInputSpecs.setType("image/*");
Intent photoInputHandler = Intent.createChooser(photoInputSpecs, "Choose a file");
startActivityForResult(photoInputHandler, READ_IN_FILE);
}
// Processes the results of Activities.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
try {
// Processes the photos that the user selected
if (requestCode == READ_IN_FILE) {
// Retrieve the photo's location
Uri photoUri = data.getData();
InputStream photoInputStream = getContentResolver().openInputStream(photoUri);
System.out.println("[photoInputStream.available()] = " photoInputStream.available());
Bitmap photoBitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(),
photoUri);
// Display the selected image in the preview box
displayPhoto(photoUri);
}
}
catch (Exception ex) {
System.out.println("onActivityResult error: " ex.toString());
}
}
// Displays a specified photo in the split and single screen preview boxes.
private void displayPhoto(Uri photoUri) {
ImageView singlePreviewBox = findViewById(R.id.image_container);
singlePreviewBox.invalidate();
singlePreviewBox.setImageURI(photoUri);
ClipDrawable mClipDrawable = new ClipDrawable(singlePreviewBox.getDrawable(), 11,
ClipDrawable.HORIZONTAL);
mClipDrawable.setLevel(5000);
singlePreviewBox.setImageResource(0);
singlePreviewBox.setBackground(mClipDrawable);
}
}
Ответ №1:
Я заметил несколько проблем с вашим кодом.
Исключение Нулевого Указателя
- Если
ImageView
у вас нет изображения, ваше приложение выйдет из строя. Это то, что вам нужно проверить заранее.
Математика
mClipDrawable.setLevel((progress / 10) * 10000);
Разделение между целыми числами может привести к потере фракции. Так что вам придется либо бросить одного из них, либо обоих; как этот.
mClipDrawable.setLevel((int)((progress / 10F) * 10000F));
Использование методов
singlePreviewBox.setImageResource(0);
Вы устанавливаете изображение на свойImageView
, вскоре после того, как вы устанавливаете его другим методом. Кстати, вам даже не нужен этот метод. Даже использование этого метода неверно. Это должно было выглядеть так:
singlePreviewBox.setImageResource(R.drawable.myImage);
Комментарии:
1. В строке кода «singlePreviewBox.setImageResource(R. drawable. myImage);», я не могу жестко закодировать значение для рисования (R. drawable. myImage), так как рисоваемым может быть любое изображение, выбранное пользователем. Кроме того, когда я пытаюсь определить, есть ли в ImageView изображение с помощью «singlePreviewBox.getDrawable() != null», оно всегда возвращает значение null.
2. 1) Как я уже сказал, вам не нужна эта строка. 2) Просто используйте логическую переменную. Вставьте один
displayPhoto()
, проверьте эту переменнуюonProgressChanged()
и не забудьте установить/сбросить ее вfalse
первую очередь, вероятно, вonActivityResult()
илиonCreate()
.