如何在每次绘制到界面之前(在片段中)获取 ImageView 的高度和宽度

huangapple go评论82阅读模式
英文:

How to get ImageView Height and Width every time, before it is drawn to the UI (in a Fragment)

问题

我想将外部存储中的照片设置到(圆形)ImageView中。因此,我有一个函数,该函数要求ImageView的高度和宽度,以便裁剪图片,然后将其设置为位图。

我的问题是,这个函数在UI加载之前就被调用了。我找到了一个解决方案,即在onViewCreated中第一次调用此函数,在其中添加了一个addOnWindowFocusChangeListener监听器。这对第一次调用有效。

该片段位于ViewPager内,如果我先转到左侧的片段,然后穿过中间转到右侧,图片又消失了。

// 这对于第一次调用有效

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);

    View m = getView();
    ViewTreeObserver n = m.getViewTreeObserver();
    n.addOnWindowFocusChangeListener(new ViewTreeObserver.OnWindowFocusChangeListener() {
        @Override
        public void onWindowFocusChanged(final boolean hasFocus) {
            // 在这里执行你的操作
            ImageUtil.setPic(binding.photoRoundProfile, mCurrentPhotoPath);
        }
    });
}
// 设置图片到ImageView的函数

static public void setPic(ImageView mImageView, String pPath) {
    try {
        if (pPath == null) return;
        File f = new File(pPath);
        if (!f.exists() || f.isDirectory()) return;

        // 获取视图的尺寸
        int targetW = mImageView.getWidth();
        if (targetW == 0) targetW = mImageView.getMeasuredWidth();
        int targetH = mImageView.getHeight();
        if (targetH == 0) targetH = mImageView.getMeasuredHeight();

        // 获取位图的尺寸
        BitmapFactory.Options bmOptions = new BitmapFactory.Options();
        bmOptions.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(pPath, bmOptions);
        int photoW = bmOptions.outWidth;
        int photoH = bmOptions.outHeight;

        // 确定需要对图像进行多少缩放
        int scaleFactor = photoW / targetW; //Math.min(photoW/targetW, photoH/targetH);

        // 将图像文件解码为大小适合填充视图的位图
        bmOptions.inJustDecodeBounds = false;
        bmOptions.inSampleSize = scaleFactor;
        bmOptions.inPurgeable = true;

        Bitmap bitmap = BitmapFactory.decodeFile(pPath, bmOptions);
        Bitmap orientedBitmap = ExifUtil.rotateBitmap(pPath, bitmap);
        mImageView.setImageBitmap(orientedBitmap);

        //mImageView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
        mImageView.setAdjustViewBounds(true);
        mImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

有一个视频,可以更好地理解:https://www.loom.com/share/05c4174562d74c9bba8ff02c9072c866

英文:

I want to set a Photo from the external Storage into a (Circular)ImageView. Therefore I have a function, that asks for the ImageView Hight and Width, to crop the Picture and then sets it as Bitmap.

My Problem is, that this function gets called before the UI is loaded. I came across with the solution, that I call this function the first time, in onViewCreated, where I add a Listener to addOnWindowFocusChangeListener. This works for the first time.

The fragment is inside a ViewPager and if I go to the fragment on the left and then over the middle to the right, it is again gone.

I am completely new to StackOverflow. I appreciate every Tip, what I can do better.

//This works for the First Time
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
View m = getView();
ViewTreeObserver n = m.getViewTreeObserver();
n.addOnWindowFocusChangeListener(new ViewTreeObserver.OnWindowFocusChangeListener() {
@Override
public void onWindowFocusChanged(final boolean hasFocus) {
// do your stuff here
ImageUtil.setPic(binding.photoRoundProfile, mCurrentPhotoPath);
}
});
}
//The function where I set the Picture into the ImageView
static public void setPic(ImageView mImageView, String pPath) {
try {
if (pPath == null) return;
File f = new File(pPath);
if (!f.exists() || f.isDirectory()) return;
// Get the dimensions of the View
int targetW = mImageView.getWidth();
if (targetW == 0) targetW = mImageView.getMeasuredWidth();
int targetH = mImageView.getHeight();
if (targetH == 0) targetH = mImageView.getMeasuredHeight();
// Get the dimensions of the bitmap
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(pPath, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
// Determine how much to scale down the image
int scaleFactor = photoW / targetW; //Math.min(photoW/targetW, photoH/targetH);
// Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
Bitmap bitmap = BitmapFactory.decodeFile(pPath, bmOptions);
Bitmap orientedBitmap = ExifUtil.rotateBitmap(pPath, bitmap);
mImageView.setImageBitmap(orientedBitmap);
//mImageView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
mImageView.setAdjustViewBounds(true);
mImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
} catch (Exception e) {
e.printStackTrace();
}
}

There is a video, for better understanding: https://www.loom.com/share/05c4174562d74c9bba8ff02c9072c866

答案1

得分: 0

我找到了解决我的问题的方法。我在OnPreDrawListener中找到了方法onPreDraw。该监听器每次更新ImageView时都会运行。因此,我添加了一个if语句来节省性能,避免每次都重新绘制。

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);

    ImageView iv= binding.photoRoundProfile;
    ViewTreeObserver vto = iv.getViewTreeObserver();
    vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {

        private int mFinalWidth = 0;
        private int mFinalHeight = 0;

        public boolean onPreDraw() {

            if(mFinalHeight != 0 || mFinalWidth != 0)
                return true;

            mFinalHeight = iv.getHeight();
            mFinalWidth = iv.getWidth();
            Log.d("hilength","Height: " + mFinalHeight + " Width: " + mFinalWidth);

            ImageUtil.setPic(binding.photoRoundProfile, mCurrentPhotoPath);
            return true;
        }
    });
}
英文:

I found a solution to my problem. I have found the Method onPreDraw in OnPreDrawListener. This Listener runs every time the ImageView is updated. Therefore I added an if-Statement to save performance and not redrawing every time.

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ImageView iv= binding.photoRoundProfile;
ViewTreeObserver vto = iv.getViewTreeObserver();
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
private int mFinalWidth = 0;
private int mFinalHeight = 0;
public boolean onPreDraw() {
if(mFinalHeight != 0 || mFinalWidth != 0)
return true;
mFinalHeight = iv.getHeight();
mFinalWidth = iv.getWidth();
Log.d("hilength","Height: " + mFinalHeight + " Width: " + mFinalWidth);
ImageUtil.setPic(binding.photoRoundProfile, mCurrentPhotoPath);
return true;
}
});
}

huangapple
  • 本文由 发表于 2020年8月26日 23:40:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/63601073.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定