-
Notifications
You must be signed in to change notification settings - Fork 3.1k
[ShapeableImageView] Fix padding bugs #2280
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
9f4d553
7d8ed42
3e6a663
e010ee5
199d595
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,8 +37,6 @@ | |
import android.graphics.RectF; | ||
import android.os.Build.VERSION; | ||
import android.os.Build.VERSION_CODES; | ||
import androidx.appcompat.content.res.AppCompatResources; | ||
import androidx.appcompat.widget.AppCompatImageView; | ||
import android.util.AttributeSet; | ||
import android.view.View; | ||
import android.view.ViewOutlineProvider; | ||
|
@@ -48,6 +46,8 @@ | |
import androidx.annotation.NonNull; | ||
import androidx.annotation.Nullable; | ||
import androidx.annotation.RequiresApi; | ||
import androidx.appcompat.content.res.AppCompatResources; | ||
import androidx.appcompat.widget.AppCompatImageView; | ||
import com.google.android.material.resources.MaterialResources; | ||
import com.google.android.material.shape.MaterialShapeDrawable; | ||
import com.google.android.material.shape.ShapeAppearanceModel; | ||
|
@@ -169,15 +169,15 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | |
return; | ||
} | ||
|
||
if (VERSION.SDK_INT > 19 && !isLayoutDirectionResolved()) { | ||
if (VERSION.SDK_INT >= 19 && !isLayoutDirectionResolved()) { | ||
return; | ||
} | ||
|
||
hasAdjustedPaddingAfterLayoutDirectionResolved = true; | ||
|
||
// Update the super padding to be the combined `android:padding` and | ||
// `app:contentPadding`, keeping with ShapeableImageView's internal padding contract: | ||
if (VERSION.SDK_INT >= 21 && (isPaddingRelative() || isContentPaddingRelative())) { | ||
if (VERSION.SDK_INT >= 17 && (isPaddingRelative() || isContentPaddingRelative())) { | ||
setPaddingRelative( | ||
super.getPaddingStart(), | ||
super.getPaddingTop(), | ||
|
@@ -219,13 +219,17 @@ public void setContentPadding( | |
startContentPadding = UNDEFINED_PADDING; | ||
endContentPadding = UNDEFINED_PADDING; | ||
|
||
// Super padding is equal to background padding + content padding. Adjust the content padding | ||
// portion of the super padding here: | ||
super.setPadding( | ||
super.getPaddingLeft() - leftContentPadding + left, | ||
super.getPaddingTop() - topContentPadding + top, | ||
super.getPaddingRight() - rightContentPadding + right, | ||
super.getPaddingBottom() - bottomContentPadding + bottom); | ||
// If onMeasure hasn't adjusted padding yet, wait for it to be set to avoid double-applying the | ||
// content padding in onMeasure: | ||
if (hasAdjustedPaddingAfterLayoutDirectionResolved) { | ||
// Super padding is equal to background padding + content padding. Adjust the content padding | ||
// portion of the super padding here: | ||
super.setPadding( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like there might be a bug if content padding are set twice, and the first time hasAdjustedPaddingAfterLayoutDirectionResolved is false and the second time it's true. At the second call, super's paddings are not actually updated with content paddings yet, so subtracting the content paddings will causes extra paddings being subtracted. Can you also add test cases for this situation after you fix it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At your second call to In any case I'll look to add tests that check this. |
||
super.getPaddingLeft() - leftContentPadding + left, | ||
super.getPaddingTop() - topContentPadding + top, | ||
super.getPaddingRight() - rightContentPadding + right, | ||
super.getPaddingBottom() - bottomContentPadding + bottom); | ||
} | ||
|
||
leftContentPadding = left; | ||
topContentPadding = top; | ||
|
@@ -244,14 +248,20 @@ public void setContentPadding( | |
@RequiresApi(17) | ||
public void setContentPaddingRelative( | ||
@Dimension int start, @Dimension int top, @Dimension int end, @Dimension int bottom) { | ||
// Super padding is equal to background padding + content padding. Adjust the content padding | ||
// portion of the super padding here: | ||
super.setPaddingRelative( | ||
super.getPaddingStart() - getContentPaddingStart() + start, | ||
super.getPaddingTop() - topContentPadding + top, | ||
super.getPaddingEnd() - getContentPaddingEnd() + end, | ||
super.getPaddingBottom() - bottomContentPadding + bottom); | ||
// If onMeasure hasn't adjusted padding yet, wait for it to be set to avoid double-applying the | ||
// content padding in onMeasure: | ||
if (hasAdjustedPaddingAfterLayoutDirectionResolved) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ditto |
||
// Super padding is equal to background padding + content padding. Adjust the content padding | ||
// portion of the super padding here: | ||
super.setPaddingRelative( | ||
super.getPaddingStart() - getContentPaddingStart() + start, | ||
super.getPaddingTop() - topContentPadding + top, | ||
super.getPaddingEnd() - getContentPaddingEnd() + end, | ||
super.getPaddingBottom() - bottomContentPadding + bottom); | ||
} | ||
|
||
startContentPadding = start; | ||
endContentPadding = end; | ||
leftContentPadding = isRtl() ? end : start; | ||
topContentPadding = top; | ||
rightContentPadding = isRtl() ? start : end; | ||
|
@@ -364,11 +374,15 @@ private boolean isRtl() { | |
@Override | ||
public void setPadding( | ||
@Dimension int left, @Dimension int top, @Dimension int right, @Dimension int bottom) { | ||
super.setPadding( | ||
left + getContentPaddingLeft(), | ||
top + getContentPaddingTop(), | ||
right + getContentPaddingRight(), | ||
bottom + getContentPaddingBottom()); | ||
if (hasAdjustedPaddingAfterLayoutDirectionResolved) { | ||
super.setPadding( | ||
left + getContentPaddingLeft(), | ||
top + getContentPaddingTop(), | ||
right + getContentPaddingRight(), | ||
bottom + getContentPaddingBottom()); | ||
} else { | ||
super.setPadding(left, top, right, bottom); | ||
} | ||
} | ||
|
||
/** | ||
|
@@ -383,11 +397,15 @@ public void setPadding( | |
@Override | ||
public void setPaddingRelative( | ||
@Dimension int start, @Dimension int top, @Dimension int end, @Dimension int bottom) { | ||
super.setPaddingRelative( | ||
start + getContentPaddingStart(), | ||
top + getContentPaddingTop(), | ||
end + getContentPaddingEnd(), | ||
bottom + getContentPaddingBottom()); | ||
if (hasAdjustedPaddingAfterLayoutDirectionResolved) { | ||
super.setPaddingRelative( | ||
start + getContentPaddingStart(), | ||
top + getContentPaddingTop(), | ||
end + getContentPaddingEnd(), | ||
bottom + getContentPaddingBottom()); | ||
} else { | ||
super.setPaddingRelative(start, top, end, bottom); | ||
} | ||
} | ||
|
||
/** | ||
|
@@ -398,7 +416,11 @@ public void setPaddingRelative( | |
@Override | ||
@Dimension | ||
public int getPaddingBottom() { | ||
return super.getPaddingBottom() - getContentPaddingBottom(); | ||
if (hasAdjustedPaddingAfterLayoutDirectionResolved) { | ||
return super.getPaddingBottom() - getContentPaddingBottom(); | ||
} else { | ||
return super.getPaddingBottom(); | ||
} | ||
} | ||
|
||
/** | ||
|
@@ -409,7 +431,11 @@ public int getPaddingBottom() { | |
@Override | ||
@Dimension | ||
public int getPaddingEnd() { | ||
return super.getPaddingEnd() - getContentPaddingEnd(); | ||
if (hasAdjustedPaddingAfterLayoutDirectionResolved) { | ||
return super.getPaddingEnd() - getContentPaddingEnd(); | ||
} else { | ||
return super.getPaddingEnd(); | ||
} | ||
} | ||
|
||
/** | ||
|
@@ -420,7 +446,11 @@ public int getPaddingEnd() { | |
@Override | ||
@Dimension | ||
public int getPaddingLeft() { | ||
return super.getPaddingLeft() - getContentPaddingLeft(); | ||
if (hasAdjustedPaddingAfterLayoutDirectionResolved) { | ||
return super.getPaddingLeft() - getContentPaddingLeft(); | ||
} else { | ||
return super.getPaddingLeft(); | ||
} | ||
} | ||
|
||
/** | ||
|
@@ -431,7 +461,11 @@ public int getPaddingLeft() { | |
@Override | ||
@Dimension | ||
public int getPaddingRight() { | ||
return super.getPaddingRight() - getContentPaddingRight(); | ||
if (hasAdjustedPaddingAfterLayoutDirectionResolved) { | ||
return super.getPaddingRight() - getContentPaddingRight(); | ||
} else { | ||
return super.getPaddingRight(); | ||
} | ||
} | ||
|
||
/** | ||
|
@@ -442,7 +476,11 @@ public int getPaddingRight() { | |
@Override | ||
@Dimension | ||
public int getPaddingStart() { | ||
return super.getPaddingStart() - getContentPaddingStart(); | ||
if (hasAdjustedPaddingAfterLayoutDirectionResolved) { | ||
return super.getPaddingStart() - getContentPaddingStart(); | ||
} else { | ||
return super.getPaddingStart(); | ||
} | ||
} | ||
|
||
/** | ||
|
@@ -453,7 +491,11 @@ public int getPaddingStart() { | |
@Override | ||
@Dimension | ||
public int getPaddingTop() { | ||
return super.getPaddingTop() - getContentPaddingTop(); | ||
if (hasAdjustedPaddingAfterLayoutDirectionResolved) { | ||
return super.getPaddingTop() - getContentPaddingTop(); | ||
} else { | ||
return super.getPaddingTop(); | ||
} | ||
} | ||
|
||
@Override | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<!-- | ||
Copyright 2019 The Android Open Source Project | ||
|
||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
|
||
http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
--> | ||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||
xmlns:tools="http://schemas.android.com/tools" | ||
package="com.google.android.material.imageview"> | ||
|
||
<uses-sdk | ||
tools:overrideLibrary="androidx.test.core"/> | ||
|
||
<application/> | ||
</manifest> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this affect API >= 19?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes,
hasAdjustedPaddingAfterLayoutDirectionResolved
doesn't get set until afteronMeasure
runs afterisLayoutDirectionResolved
(which is an API 19+ method) becomes true. (So really it affects 19+ more than it affects pre-19.)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it. Don't you need to call setContentPadding() again when hasAdjustedPaddingAfterLayoutDirectionResolved is set to true? So the previous set content paddings can be applied?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No.
setContentPadding
does two things:super.setPadding
according to this class's internal padding contract. This is skipped if this flag is not set, butsuper.setPadding
is also called immediately after the flag is set, so this call is covered either way.contentPadding
variables, regardless of whether that flag is set.The private
contentPadding
variables are only used in thegetContentPadding
andgetPadding
getters.updateShapeMask
uses thegetPadding
getters to set the shape size, so now I wonder if I need to force a call toupdateShapeMask
immediately after that flag is set too...There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good catch. I think onSizeChanged() will be called after setting paddings, right? That should be fine I guess.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think
onSizeChanged
is not called in that case actually. I'll need to try to force an error this way to be sure, and add a related test if possible