Android:ViewPager WRAP_CONTENT를 사용할 수 없습니다.
각 페이지마다 높이가 200dp인 ImageView가 있는 간단한 ViewPager를 설정했습니다.
여기 내 호출기가 있습니다.
pager = new ViewPager(this);
pager.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
pager.setBackgroundColor(Color.WHITE);
pager.setOnPageChangeListener(listener);
layout.addView(pager);
wrap_content로 설정된 높이에도 불구하고 이미지 보기가 200dp에 불과하더라도 호출기는 항상 화면을 채웁니다.호출기의 높이를 "200"으로 바꾸려고 했지만 여러 해상도로 다른 결과를 얻었습니다.저는 그 값에 "dp"를 추가할 수 없습니다.호출기 레이아웃에 200dp를 추가하려면 어떻게 해야 합니까?
의 사용 측에의 에 우선합니다.ViewPager
다음과 같이 현재 가장 큰 아이의 키를 얻을 수 있습니다.
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int height = 0;
int childWidthSpec = MeasureSpec.makeMeasureSpec(
Math.max(0, MeasureSpec.getSize(widthMeasureSpec) -
getPaddingLeft() - getPaddingRight()),
MeasureSpec.getMode(widthMeasureSpec)
);
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
child.measure(childWidthSpec, MeasureSpec.UNSPECIFIED);
int h = child.getMeasuredHeight();
if (h > height) height = h;
}
if (height != 0) {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
또 다른 일반적인 솔루션은 다음과 같습니다.wrap_content
그냥 일하기 위해서요.
장했습다.ViewPager
무시하는onMeasure()
높이는 첫 번째 자식 보기 주위에 감겨 있습니다.이로 인해 하위 보기의 높이가 정확히 동일하지 않을 경우 예상치 못한 결과가 발생할 수 있습니다.이를 위해 클래스를 현재 보기/페이지 크기에 맞게 쉽게 확장할 수 있습니다.하지만 난 그게 필요하지 않았어요.
이 ViewPager는 원래 ViewPager와 마찬가지로 XML 레이아웃에서 사용할 수 있습니다.
<view
android:layout_width="match_parent"
android:layout_height="wrap_content"
class="de.cybergen.ui.layout.WrapContentHeightViewPager"
android:id="@+id/wrapContentHeightViewPager"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"/>
장점:이 방법을 사용하면 상대 레이아웃을 포함한 모든 레이아웃에서 ViewPager를 사용하여 다른 UI 요소를 오버레이할 수 있습니다.
한 가지 단점이 남아 있습니다.여백을 사용하려면 두 개의 중첩된 레이아웃을 만들고 내부 레이아웃에 원하는 여백을 지정해야 합니다.
코드는 다음과 같습니다.
public class WrapContentHeightViewPager extends ViewPager {
/**
* Constructor
*
* @param context the context
*/
public WrapContentHeightViewPager(Context context) {
super(context);
}
/**
* Constructor
*
* @param context the context
* @param attrs the attribute set
*/
public WrapContentHeightViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// find the first child view
View view = getChildAt(0);
if (view != null) {
// measure the first child view with the specified measure spec
view.measure(widthMeasureSpec, heightMeasureSpec);
}
setMeasuredDimension(getMeasuredWidth(), measureHeight(heightMeasureSpec, view));
}
/**
* Determines the height of this view
*
* @param measureSpec A measureSpec packed into an int
* @param view the base view with already measured height
*
* @return The height of the view, honoring constraints from measureSpec
*/
private int measureHeight(int measureSpec, View view) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else {
// set the height from the base view if available
if (view != null) {
result = view.getMeasuredHeight();
}
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);
}
}
return result;
}
}
저는 다니엘 로페즈 라칼레와 이 게시물 http://www.henning.ms/2013/09/09/viewpager-that-simply-dont-measure-up/ 을 기반으로 답변을 했습니다.다니엘의 대답의 문제는 어떤 경우에는 제 아이들의 키가 0이라는 것입니다.그 해결책은 불행히도 두 번 측정하는 것이었습니다.
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int mode = MeasureSpec.getMode(heightMeasureSpec);
// Unspecified means that the ViewPager is in a ScrollView WRAP_CONTENT.
// At Most means that the ViewPager is not in a ScrollView WRAP_CONTENT.
if (mode == MeasureSpec.UNSPECIFIED || mode == MeasureSpec.AT_MOST) {
// super has to be called in the beginning so the child views can be initialized.
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int height = 0;
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
int h = child.getMeasuredHeight();
if (h > height) height = h;
}
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
}
// super has to be called again so the new specs are treated as exact measurements
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
이렇게 하면 원하는 경우 ViewPager의 높이를 설정할 수도 있고 내용을 랩핑할 수도 있습니다.
저는 방금 이와 관련된 매우 유사한 질문에 답하고 있었는데, 제 주장을 뒷받침할 링크를 찾다가 우연히 이것을 발견했습니다. 행운입니다 :)
또 다른 대답은: 른다대답은내▁my:다른은답:
는 ViewPager를 지원하지 .wrap_content
(일반적으로) 모든 하위 항목을 동시에 로드하지 않으므로 적절한 크기를 얻을 수 없습니다(페이지를 전환할 때마다 크기를 변경하는 호출기가 옵션일 수 있음).
한 치수 150dp와 "150dp"를 할 수 .match_parent
작동하기도 합니다.
또한 코드에서 치수를 동적으로 수정할 수 있습니다.height
-그 안에 있는LayoutParams
.
필요에 따라 layout_height를 200dp로 설정한 자체 xml 파일로 ViewPager를 만든 다음 코드에서 처음부터 새 ViewPager를 만드는 대신 해당 xml 파일을 부풀릴 수 있습니다.
LayoutInflater inflater = context.getLayoutInflater();
inflater.inflate(R.layout.viewpagerxml, layout, true);
Daniel López Localle 답변을 사용하여 코틀린에서 이 클래스를 만들었습니다.시간이 더 절약되길 바랍니다.
class DynamicHeightViewPager @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : ViewPager(context, attrs) {
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
var heightMeasureSpec = heightMeasureSpec
var height = 0
for (i in 0 until childCount) {
val child = getChildAt(i)
child.measure(widthMeasureSpec, View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED))
val h = child.measuredHeight
if (h > height) height = h
}
if (height != 0) {
heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY)
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
}}
저는 방금 같은 문제에 부딪혔습니다.저는 ViewPager를 가지고 있었고 그 버튼에 광고를 표시하고 싶었습니다.제가 찾은 해결책은 호출기를 RelativeView로 가져와서 위의 레이아웃을 아래에서 보고 싶은 뷰 ID로 설정하는 것이었습니다. 그것은 저에게 효과가 있었습니다.
여기 내 레이아웃 XML이 있습니다.
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:id="@+id/AdLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="vertical" >
</LinearLayout>
<android.support.v4.view.ViewPager
android:id="@+id/mainpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/AdLayout" >
</android.support.v4.view.ViewPager>
</RelativeLayout>
저는 이미 여러 프로젝트에서 이 문제에 직면했지만 완벽한 해결책을 가진 적이 없습니다.그래서 저는 ViewPager를 대체하기 위해 WrapContentViewPager github 프로젝트를 만들었습니다.
https://github.com/rnevet/WCViewPager
이 솔루션은 여기에 제시된 몇 가지 답변에서 영감을 얻었지만 다음과 같이 개선되었습니다.
- 스크롤하는 동안을 포함하여 현재 보기에 따라 ViewPager 높이를 동적으로 변경합니다.
- PagerTabStrip과 같은 "장식" 보기의 높이를 고려합니다.
- 모든 패딩을 고려합니다.
이전 구현을 중단한 지원 라이브러리 버전 24에 대해 업데이트되었습니다.
, 저 에는 나도이문부지만딪혔는경, 나우에의에제▁a는▁had,▁i에경우,▁but▁i나▁problem▁in▁my만의▁this▁ran▁into나지.FragmentPagerAdapter
그것은 공급하고 있었습니다.ViewPager
그 페이지들과 함께.내가 가지고 있던 문제는onMeasure()
의 시대의ViewPager
어느 누구보다도 먼저 불려졌습니다.Fragments
생성되었기 때문에 크기를 올바르게 조정할 수 없습니다.
약간의 시행착오 끝에, 저는 그것을 발견했습니다.finishUpdate()
는 fragmentPagerAdapter 메서다호다니출 됩니다.Fragments
)로부터) 되었습니다.instantiateItem()
에 시대에FragmentPagerAdapter
및 후에도 표시됩니다. 및 페이지 스크롤 후/중에도 표시됩니다.작은 인터페이스를 만들었습니다.
public interface AdapterFinishUpdateCallbacks
{
void onFinishUpdate();
}
나는 그것을 나의 것으로 넘깁니다.FragmentPagerAdapter
통화:
@Override
public void finishUpdate(ViewGroup container)
{
super.finishUpdate(container);
if (this.listener != null)
{
this.listener.onFinishUpdate();
}
}
결국 전화할 수 있게 해줍니다.setVariableHeight()
돈으로CustomViewPager
구현:
public void setVariableHeight()
{
// super.measure() calls finishUpdate() in adapter, so need this to stop infinite loop
if (!this.isSettingHeight)
{
this.isSettingHeight = true;
int maxChildHeight = 0;
int widthMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY);
for (int i = 0; i < getChildCount(); i++)
{
View child = getChildAt(i);
child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(ViewGroup.LayoutParams.WRAP_CONTENT, MeasureSpec.UNSPECIFIED));
maxChildHeight = child.getMeasuredHeight() > maxChildHeight ? child.getMeasuredHeight() : maxChildHeight;
}
int height = maxChildHeight + getPaddingTop() + getPaddingBottom();
int heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.measure(widthMeasureSpec, heightMeasureSpec);
requestLayout();
this.isSettingHeight = false;
}
}
저는 그것이 최선의 접근법인지 확신할 수 없습니다. 만약 당신이 그것이 좋다고 생각한다면 논평을 좋아할 것입니다. 하지만 그것은 제 구현에서 꽤 잘 작동하는 것 같습니다. :)
이것이 누군가에게 도움이 되기를 바랍니다!
편집: 추가하는 것을 잊었습니다.requestLayout()
화를한후에전을 부른 super.measure()
(보기가 다시 그려지지 않는 경우).
저는 또한 부모님의 패딩을 최종 높이에 추가하는 것을 잊었습니다.
또한 원래 너비/높이 MeasureSpec을 유지하지 않고 필요에 따라 새 MeasureSpec을 만듭니다.그에 따라 코드를 업데이트합니다.
제가 가진 또 다른 문제는 그것이 크기가 정확하지 않다는 것이었습니다.ScrollView
그리고 범인이 아이를 측정하는 것을 발견했습니다.MeasureSpec.EXACTLY
에 MeasureSpec.UNSPECIFIED
이를 반영하여 업데이트되었습니다.
이러한 변경 사항이 모두 코드에 추가되었습니다.원하는 경우 기록을 확인하여 이전(잘못된) 버전을 볼 수 있습니다.
은 다른솔업입다니트데이를 업데이트하는 것입니다.ViewPager
지높따높의 현재 에 따른 PagerAdapter
당신의 를한다가니다합을 만들고 합니다.ViewPager
페이지를 이 방식으로:
@Override
public Object instantiateItem(ViewGroup container, int position) {
PageInfo item = mPages.get(position);
item.mImageView = new CustomImageView(container.getContext());
item.mImageView.setImageDrawable(item.mDrawable);
container.addView(item.mImageView, 0);
return item;
}
에▁where디mPages
는 의내목다니의 입니다.PageInfo
동로추가구에 PagerAdapter
그리고.CustomImageView
정기적으로 하는 거예요.ImageView
onMeasure()
지정된 너비에 따라 높이를 설정하고 이미지 가로 세로 비율을 유지하는 방법입니다.
강제할 수 있습니다.ViewPager
의 높이setPrimaryItem()
방법:
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
super.setPrimaryItem(container, position, object);
PageInfo item = (PageInfo) object;
ViewPager pager = (ViewPager) container;
int width = item.mImageView.getMeasuredWidth();
int height = item.mImageView.getMeasuredHeight();
pager.setLayoutParams(new FrameLayout.LayoutParams(width, Math.max(height, 1)));
}
에 하십시오.Math.max(height, 1)
그것은 성가신 버그를 고칩니다.ViewPager
이전 페이지의 높이가 0인 경우 표시된 페이지를 업데이트하지 않습니다(공백으로 유지). 즉, Null을 그릴 수 있습니다.CustomImageView
각는 두 로 스와이프합니다.), 각 홀 는 수 를 사 이 앞 로 뒤 스 프 합 이 와 니 다 지 페 이 두 합 프 ▁), 니 ▁each ▁back 다 이 스
뷰 페이지 내에서 정적 콘텐츠를 사용하고 화려한 애니메이션을 원하지 않을 때는 다음 뷰 페이지를 사용할 수 있습니다.
public class HeightWrappingViewPager extends ViewPager {
public HeightWrappingViewPager(Context context) {
super(context);
}
public HeightWrappingViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
View firstChild = getChildAt(0);
firstChild.measure(widthMeasureSpec, heightMeasureSpec);
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(firstChild.getMeasuredHeight(), MeasureSpec.EXACTLY));
}
}
개선된 다니엘 로페즈 라칼레의 대답은 코틀린으로 다시 작성되었습니다.
class MyViewPager(context: Context, attrs: AttributeSet): ViewPager(context, attrs) {
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val zeroHeight = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
val maxHeight = children
.map { it.measure(widthMeasureSpec, zeroHeight); it.measuredHeight }
.max() ?: 0
if (maxHeight > 0) {
val maxHeightSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.EXACTLY)
super.onMeasure(widthMeasureSpec, maxHeightSpec)
return
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
}
}
위에서 제시한 어떤 것도 저에게는 효과가 없었습니다. 사례는 용개사 4의정의사 ViewPager를에 정의 입니다.ScrollView
그 중 상단은 가로 세로 비율을 기준으로 측정되고 나머지는 다음과 같이 측정됩니다.layout_height=wrap_content
사이버젠, 다니엘 로페즈 라칼레 해결책을 시도해봤어요그들 중 누구도 저를 위해 완벽하게 일하지 않습니다.
제 추측으로는 사이버젠이 > 1페이지에서 작동하지 않는 이유는 1페이지를 기준으로 호출기의 높이를 계산하기 때문인데, 이는 더 스크롤하면 숨겨져 있습니다.
cybergen과 Daniel López Lacale 제안 모두 이상한 행동을 보입니다. 제 경우 3개 중 2개는 정상이고 1개는 무작위로 높이가 0입니다.표시됨onMeasure
아이들이 채워지기 전에 호출되었습니다.그래서 저는 다음 두 가지 답과 저만의 해결책을 혼합하여 생각해냈습니다.
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT) {
// find the first child view
View view = getChildAt(0);
if (view != null) {
// measure the first child view with the specified measure spec
view.measure(widthMeasureSpec, heightMeasureSpec);
int h = view.getMeasuredHeight();
setMeasuredDimension(getMeasuredWidth(), h);
//do not recalculate height anymore
getLayoutParams().height = h;
}
}
}
아이디어는 내버려두는 것입니다.ViewPager
어린이 치수를 계산하고 계산된 첫 페이지의 높이를 레이아웃 매개변수에 저장합니다.ViewPager
조각의 레이아웃 높이를 다음으로 설정하는 것을 잊지 마십시오.wrap_content
그렇지 않으면 높이=0을 얻을 수 있습니다.나는 이것을 사용했습니다.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- Childs are populated in fragment -->
</LinearLayout>
이 솔루션은 모든 페이지의 높이가 동일할 경우 매우 유용합니다.그렇지 않으면 다시 계산해야 합니다.ViewPager
현재 활성 상태의 어린이를 기준으로 한 높이입니다.필요는 없지만, 해결책을 제시해 주시면 기꺼이 답변을 업데이트하겠습니다.
public CustomPager (Context context) {
super(context);
}
public CustomPager (Context context, AttributeSet attrs) {
super(context, attrs);
}
int getMeasureExactly(View child, int widthMeasureSpec) {
child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
int height = child.getMeasuredHeight();
return MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
boolean wrapHeight = MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST;
final View tab = getChildAt(0);
if (tab == null) {
return;
}
int width = getMeasuredWidth();
if (wrapHeight) {
// Keep the current measured width.
widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
}
Fragment fragment = ((Fragment) getAdapter().instantiateItem(this, getCurrentItem()));
heightMeasureSpec = getMeasureExactly(fragment.getView(), widthMeasureSpec);
//Log.i(Constants.TAG, "item :" + getCurrentItem() + "|height" + heightMeasureSpec);
// super has to be called again so the new specs are treated as
// exact measurements.
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
팝콘 타임 안드로이드 앱의 소스 코드에서 현재 아이의 크기에 따라 멋진 애니메이션으로 뷰페이지 크기를 동적으로 조정하는 솔루션을 찾았습니다.
public class WrappingViewPager extends ViewPager {
private Boolean mAnimStarted = false;
public WrappingViewPager(Context context) {
super(context);
}
public WrappingViewPager(Context context, AttributeSet attrs){
super(context, attrs);
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if(!mAnimStarted && null != getAdapter()) {
int height = 0;
View child = ((FragmentPagerAdapter) getAdapter()).getItem(getCurrentItem()).getView();
if (child != null) {
child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
height = child.getMeasuredHeight();
if (VersionUtils.isJellyBean() && height < getMinimumHeight()) {
height = getMinimumHeight();
}
}
// Not the best place to put this animation, but it works pretty good.
int newHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
if (getLayoutParams().height != 0 && heightMeasureSpec != newHeight) {
final int targetHeight = height;
final int currentHeight = getLayoutParams().height;
final int heightChange = targetHeight - currentHeight;
Animation a = new Animation() {
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
if (interpolatedTime >= 1) {
getLayoutParams().height = targetHeight;
} else {
int stepHeight = (int) (heightChange * interpolatedTime);
getLayoutParams().height = currentHeight + stepHeight;
}
requestLayout();
}
@Override
public boolean willChangeBounds() {
return true;
}
};
a.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
mAnimStarted = true;
}
@Override
public void onAnimationEnd(Animation animation) {
mAnimStarted = false;
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
a.setDuration(1000);
startAnimation(a);
mAnimStarted = true;
} else {
heightMeasureSpec = newHeight;
}
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
가장 큰 아이뿐만 아니라 모든 아이들에게 크기를 조정하는 ViewPager가 필요할 때를 대비하여, 저는 그것을 하는 코드를 작성했습니다.해당 변경 사항에 대한 애니메이션은 없습니다(내 경우에는 필요하지 않음).
Android:minHeight 플래그도 지원됩니다.
public class ChildWrappingAdjustableViewPager extends ViewPager {
List<Integer> childHeights = new ArrayList<>(getChildCount());
int minHeight = 0;
int currentPos = 0;
public ChildWrappingAdjustableViewPager(@NonNull Context context) {
super(context);
setOnPageChangeListener();
}
public ChildWrappingAdjustableViewPager(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
obtainMinHeightAttribute(context, attrs);
setOnPageChangeListener();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
childHeights.clear();
//calculate child views
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
int h = child.getMeasuredHeight();
if (h < minHeight) {
h = minHeight;
}
childHeights.add(i, h);
}
if (childHeights.size() - 1 >= currentPos) {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(childHeights.get(currentPos), MeasureSpec.EXACTLY);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
private void obtainMinHeightAttribute(@NonNull Context context, @Nullable AttributeSet attrs) {
int[] heightAttr = new int[]{android.R.attr.minHeight};
TypedArray typedArray = context.obtainStyledAttributes(attrs, heightAttr);
minHeight = typedArray.getDimensionPixelOffset(0, -666);
typedArray.recycle();
}
private void setOnPageChangeListener() {
this.addOnPageChangeListener(new SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
currentPos = position;
ViewGroup.LayoutParams layoutParams = ChildWrappingAdjustableViewPager.this.getLayoutParams();
layoutParams.height = childHeights.get(position);
ChildWrappingAdjustableViewPager.this.setLayoutParams(layoutParams);
ChildWrappingAdjustableViewPager.this.invalidate();
}
});
}
}
저는 같은 문제에 부딪혔고, 사용자가 페이지 사이를 스크롤할 때 ViewPager가 내용을 감싸도록 해야 했습니다.사이버젠의 위 답변을 사용하여 onMeasure 방법을 다음과 같이 정의했습니다.
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (getCurrentItem() < getChildCount()) {
View child = getChildAt(getCurrentItem());
if (child.getVisibility() != GONE) {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec),
MeasureSpec.UNSPECIFIED);
child.measure(widthMeasureSpec, heightMeasureSpec);
}
setMeasuredDimension(getMeasuredWidth(), measureHeight(heightMeasureSpec, getChildAt(getCurrentItem())));
}
}
이러한 방식으로 onMeasure 방법은 ViewPager에 의해 표시되는 현재 페이지의 높이를 설정합니다.
이 문제를 겪고 C#에서 Xamarin Android를 코딩하는 사용자에게는 다음과 같은 빠른 해결책이 될 수 있습니다.
pager.ChildViewAdded += (sender, e) => {
e.Child.Measure ((int)MeasureSpecMode.Unspecified, (int)MeasureSpecMode.Unspecified);
e.Parent.LayoutParameters.Height = e.Child.MeasuredHeight;
};
이 기능은 주로 하위 보기의 높이가 같은 경우에 유용합니다.그렇지 않으면, 당신은 어떤 종류의 "최소"를 저장해야 할 것입니다.높이" 값은 확인하는 모든 하위 항목에 대한 값이며, 작은 하위 항목 보기 아래에 빈 공간이 표시되지 않도록 할 수도 있습니다.
솔루션 자체는 저에게 충분하지 않지만, 제 하위 항목이 listViews 및 Measured이기 때문입니다.높이가 올바르게 계산되지 않은 것 같습니다.
WrapContent 버전이 있습니다.선택한 현재 자식 뷰에서 부모 뷰의 높이 기준 크기를 조정하는 API 23 이전에 올바르게 작동했던 높이 보기 페이지입니다.
API 23으로 업그레이드한 후 작동을 중지했습니다.오래된 솔루션이 사용 중이었던 것으로 밝혀졌습니다.getChildAt(getCurrentItem())
작동하지 않는 항목을 측정하기 위해 현재 하위 뷰를 가져옵니다.여기에서 솔루션을 확인하십시오. https://stackoverflow.com/a/16512217/1265583
아래는 API 23과 함께 작동합니다.
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int height = 0;
ViewPagerAdapter adapter = (ViewPagerAdapter)getAdapter();
View child = adapter.getItem(getCurrentItem()).getView();
if(child != null) {
child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
height = child.getMeasuredHeight();
}
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
아래 코드가 저에게 유일하게 효과가 있었습니다.
이 클래스를 사용하여 HeightWrapingViewPager를 선언합니다.
public class HeightWrappingViewPager extends ViewPager {
public HeightWrappingViewPager(Context context) {
super(context);
}
public HeightWrappingViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int mode = MeasureSpec.getMode(heightMeasureSpec);
// Unspecified means that the ViewPager is in a ScrollView WRAP_CONTENT.
// At Most means that the ViewPager is not in a ScrollView WRAP_CONTENT.
if (mode == MeasureSpec.UNSPECIFIED || mode == MeasureSpec.AT_MOST) {
// super has to be called in the beginning so the child views can be initialized.
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int height = 0;
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
int h = child.getMeasuredHeight();
if (h > height) height = h;
}
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
}
// super has to be called again so the new specs are treated as exact measurements
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
xml 파일에 높이 래핑 보기 호출기를 삽입합니다.
<com.project.test.HeightWrappingViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.project.test.HeightWrappingViewPager>
보기 호출기 선언:
HeightWrappingViewPager mViewPager;
mViewPager = (HeightWrappingViewPager) itemView.findViewById(R.id.pager);
CustomAdapter adapter = new CustomAdapter(context);
mViewPager.setAdapter(adapter);
mViewPager.measure(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
이 ViewPager는 현재 표시된 하위 항목으로만 크기 조정됩니다(실제 하위 항목 중 가장 큰 항목은 아님).
https://stackoverflow.com/a/56325869/4718406 의 아이디어입니다.
public class DynamicHeightViewPager extends ViewPager {
public DynamicHeightViewPager (Context context) {
super(context);
initPageChangeListener();
}
public DynamicHeightViewPager (Context context, AttributeSet attrs) {
super(context, attrs);
initPageChangeListener();
}
private void initPageChangeListener() {
addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
requestLayout();
}
});
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//View child = getChildAt(getCurrentItem());
View child = getCurrentView(this);
if (child != null) {
child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0,
MeasureSpec.UNSPECIFIED));
int h = child.getMeasuredHeight();
heightMeasureSpec = MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
View getCurrentView(ViewPager viewPager) {
try {
final int currentItem = viewPager.getCurrentItem();
for (int i = 0; i < viewPager.getChildCount(); i++) {
final View child = viewPager.getChildAt(i);
final ViewPager.LayoutParams layoutParams = (ViewPager.LayoutParams)
child.getLayoutParams();
Field f = layoutParams.getClass().getDeclaredField("position");
//NoSuchFieldException
f.setAccessible(true);
int position = (Integer) f.get(layoutParams); //IllegalAccessException
if (!layoutParams.isDecor && currentItem == position) {
return child;
}
}
} catch (NoSuchFieldException e) {
e.fillInStackTrace();
} catch (IllegalArgumentException e) {
e.fillInStackTrace();
} catch (IllegalAccessException e) {
e.fillInStackTrace();
}
return null;
}
}
선택한 항목에 따라 높이를 변경할 수 있도록 보기 페이지를 만들기 위해 cybergen 답변을 편집합니다. 클래스는 cybergen의 것과 동일하지만 모두 보기 페이지의 하위 보기 높이인 정수 벡터를 추가했으며 페이지가 업데이트 높이로 변경될 때 액세스할 수 있습니다.
이 클래스는 다음과 같습니다.
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.viewpager.widget.ViewPager;
import java.util.Vector;
public class WrapContentHeightViewPager extends ViewPager {
private Vector<Integer> heights = new Vector<>();
public WrapContentHeightViewPager(@NonNull Context context) {
super(context);
}
public WrapContentHeightViewPager(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
for(int i=0;i<getChildCount();i++) {
View view = getChildAt(i);
if (view != null) {
view.measure(widthMeasureSpec, heightMeasureSpec);
heights.add(measureHeight(heightMeasureSpec, view));
}
}
setMeasuredDimension(getMeasuredWidth(), measureHeight(heightMeasureSpec, getChildAt(0)));
}
public int getHeightAt(int position){
return heights.get(position);
}
private int measureHeight(int measureSpec, View view) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else {
if (view != null) {
result = view.getMeasuredHeight();
}
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);
}
}
return result;
}
}
그런 다음 활동에 OnPageChangeListener를 추가합니다.
WrapContentHeightViewPager viewPager = findViewById(R.id.my_viewpager);
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}
@Override
public void onPageSelected(int position) {
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) viewPager.getLayoutParams();
params.height = viewPager.getHeightAt(position);
viewPager.setLayoutParams(params);
}
@Override
public void onPageScrollStateChanged(int state) {}
});
여기 xml이 있습니다.
<com.example.example.WrapContentHeightViewPager
android:id="@+id/my_viewpager"
android:fillViewport="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
필요하다면 제 영어를 고쳐주세요.
다른 코틀린 코드
class DynamicViewPager @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : ViewPager(context, attrs) {
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
var height = 0
(0 until childCount).forEach {
val child = getChildAt(it)
child.measure(
widthMeasureSpec,
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
)
height = max(height, child.measuredHeight)
}
if (height > 0) {
super.onMeasure(
widthMeasureSpec,
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
)
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
}
}
}
에 약에만.ViewPager
당신이 사용하는 것은 아이의 아이입니다.ScrollView
AND는PagerTitleStrip
어린이 여러분은 이미 제공된 훌륭한 답변을 약간 수정해야 할 것입니다.참고로 내 XML은 다음과 같습니다.
<ScrollView
android:id="@+id/match_scroll_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@color/white">
<LinearLayout
android:id="@+id/match_and_graphs_wrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<view
android:id="@+id/pager"
class="com.printandpixel.lolhistory.util.WrapContentHeightViewPager"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v4.view.PagerTitleStrip
android:id="@+id/pager_title_strip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:background="#33b5e5"
android:paddingBottom="4dp"
android:paddingTop="4dp"
android:textColor="#fff" />
</view>
</LinearLayout>
</ScrollView>
의 신의에서.onMeasure
측정값을 추가해야 합니다.의 높이PagerTitleStrip
이 추가적인 그것의 키는 모든 중 가장 큰되지 않을입니다.그렇지 않으면 추가 공간을 차지하더라도 키가 모든 어린이 중 가장 큰 키로 간주되지 않습니다.
이것이 다른 사람에게 도움이 되기를 바랍니다.좀 엉터리라서 미안해요.
public class WrapContentHeightViewPager extends ViewPager {
public WrapContentHeightViewPager(Context context) {
super(context);
}
public WrapContentHeightViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int pagerTitleStripHeight = 0;
int height = 0;
for(int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
int h = child.getMeasuredHeight();
if (h > height) {
// get the measuredHeight of the tallest fragment
height = h;
}
if (child.getClass() == PagerTitleStrip.class) {
// store the measured height of the pagerTitleStrip if one is found. This will only
// happen if you have a android.support.v4.view.PagerTitleStrip as a direct child
// of this class in your XML.
pagerTitleStripHeight = h;
}
}
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height+pagerTitleStripHeight, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
제가 여기서 보는 대부분의 해결책은 이중 측정을 하는 것처럼 보입니다: 먼저 어린이 보기를 측정한 다음, 전화를 거는 것입니다.super.onMeasure()
나는 하나의 관습을 생각해 냈습니다.WrapContentViewPager
Fragment와 잘 작동합니다. RecyclerView 및 Fragment는 RecyclerView 및 Fragment와 잘 작동합니다.
데모는 여기에서 확인할 수 있습니다.
클래스 코드는 WrapContentViewPager.java입니다.
저의 경우 크기를 적용할 때 현재 선택된 요소와 애니메이션에 대한 wrap_content가 포함된 뷰페이지가 필요했습니다.아래에서 나의 구현을 볼 수 있습니다.누가 도움이 될 수 있을까요?
package one.xcorp.widget
import android.animation.ValueAnimator
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import one.xcorp.widget.R
import kotlin.properties.Delegates.observable
class ViewPager : android.support.v4.view.ViewPager {
var enableAnimation by observable(false) { _, _, enable ->
if (enable) {
addOnPageChangeListener(onPageChangeListener)
} else {
removeOnPageChangeListener(onPageChangeListener)
}
}
private var animationDuration = 0L
private var animator: ValueAnimator? = null
constructor (context: Context) : super(context) {
init(context, null)
}
constructor (context: Context, attrs: AttributeSet?) : super(context, attrs) {
init(context, attrs)
}
private fun init(context: Context, attrs: AttributeSet?) {
context.theme.obtainStyledAttributes(
attrs,
R.styleable.ViewPager,
0,
0
).apply {
try {
enableAnimation = getBoolean(
R.styleable.ViewPager_enableAnimation,
enableAnimation
)
animationDuration = getInteger(
R.styleable.ViewPager_animationDuration,
resources.getInteger(android.R.integer.config_shortAnimTime)
).toLong()
} finally {
recycle()
}
}
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val heightMode = MeasureSpec.getMode(heightMeasureSpec)
val measuredHeight = if (heightMode == MeasureSpec.EXACTLY) {
MeasureSpec.getSize(heightMeasureSpec)
} else {
val currentViewHeight = findViewByPosition(currentItem)?.also {
measureView(it)
}?.measuredHeight ?: 0
if (heightMode != MeasureSpec.AT_MOST) {
currentViewHeight
} else {
Math.min(
currentViewHeight,
MeasureSpec.getSize(heightMeasureSpec)
)
}
}
super.onMeasure(
widthMeasureSpec,
MeasureSpec.makeMeasureSpec(measuredHeight, MeasureSpec.EXACTLY)
)
}
private fun measureView(view: View) = with(view) {
val horizontalMode: Int
val horizontalSize: Int
when (layoutParams.width) {
MATCH_PARENT -> {
horizontalMode = MeasureSpec.EXACTLY
horizontalSize = this@ViewPager.measuredWidth
}
WRAP_CONTENT -> {
horizontalMode = MeasureSpec.UNSPECIFIED
horizontalSize = 0
}
else -> {
horizontalMode = MeasureSpec.EXACTLY
horizontalSize = layoutParams.width
}
}
val verticalMode: Int
val verticalSize: Int
when (layoutParams.height) {
MATCH_PARENT -> {
verticalMode = MeasureSpec.EXACTLY
verticalSize = this@ViewPager.measuredHeight
}
WRAP_CONTENT -> {
verticalMode = MeasureSpec.UNSPECIFIED
verticalSize = 0
}
else -> {
verticalMode = MeasureSpec.EXACTLY
verticalSize = layoutParams.height
}
}
val horizontalMeasureSpec = MeasureSpec.makeMeasureSpec(horizontalSize, horizontalMode)
val verticalMeasureSpec = MeasureSpec.makeMeasureSpec(verticalSize, verticalMode)
measure(horizontalMeasureSpec, verticalMeasureSpec)
}
private fun findViewByPosition(position: Int): View? {
for (i in 0 until childCount) {
val childView = getChildAt(i)
val childLayoutParams = childView.layoutParams as LayoutParams
val childPosition by lazy {
val field = childLayoutParams.javaClass.getDeclaredField("position")
field.isAccessible = true
field.get(childLayoutParams) as Int
}
if (!childLayoutParams.isDecor && position == childPosition) {
return childView
}
}
return null
}
private fun animateContentHeight(childView: View, fromHeight: Int, toHeight: Int) {
animator?.cancel()
if (fromHeight == toHeight) {
return
}
animator = ValueAnimator.ofInt(fromHeight, toHeight).apply {
addUpdateListener {
measureView(childView)
if (childView.measuredHeight != toHeight) {
animateContentHeight(childView, height, childView.measuredHeight)
} else {
layoutParams.height = animatedValue as Int
requestLayout()
}
}
duration = animationDuration
start()
}
}
private val onPageChangeListener = object : OnPageChangeListener {
override fun onPageScrollStateChanged(state: Int) {
/* do nothing */
}
override fun onPageScrolled(
position: Int,
positionOffset: Float,
positionOffsetPixels: Int
) {
/* do nothing */
}
override fun onPageSelected(position: Int) {
if (!isAttachedToWindow) {
return
}
findViewByPosition(position)?.let { childView ->
measureView(childView)
animateContentHeight(childView, height, childView.measuredHeight)
}
}
}
}
프로젝트에 attrs.xml 추가:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ViewPager">
<attr name="enableAnimation" format="boolean" />
<attr name="animationDuration" format="integer" />
</declare-styleable>
</resources>
사용 방법:
<one.xcorp.widget.ViewPager
android:id="@+id/wt_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:enableAnimation="true" />
ViewPager 높이 측정:
public class WrapViewPager extends ViewPager {
View primaryView;
public WrapViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (primaryView != null) {
int height = 0;
for (int i = 0; i < getChildCount(); i++) {
if (primaryView == getChildAt(i)) {
int childHeightSpec = MeasureSpec.makeMeasureSpec(0x1 << 30 - 1, MeasureSpec.AT_MOST);
getChildAt(i).measure(widthMeasureSpec, childHeightSpec);
height = getChildAt(i).getMeasuredHeight();
}
}
setMeasuredDimension(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
}
}
public void setPrimaryView(View view) {
primaryView = view;
}
}
호출 집합 PrimaryView(View) :
public class ZGAdapter extends PagerAdapter {
@Override
public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
super.setPrimaryItem(container, position, object);
((WrapViewPager)container).setPrimaryView((View)object);
}
}
저도 비슷한 시나리오가 있습니다(그러나 복잡한 시나리오입니다.ViewPager가 포함된 대화상자가 있습니다.
하위 페이지 중 하나가 정적 높이의 짧은 페이지입니다.
다른 하위 페이지는 항상 가능한 높이여야 합니다.
다른 하위 페이지에는 ScrollView가 포함되어 있으며 ScrollView 내용이 대화 상자에 사용할 수 있는 전체 높이가 필요하지 않으면 페이지(및 전체 대화 상자)가 WRAP_CONTENT여야 합니다.
이 특정 시나리오에 대해 기존의 답변 중 완전히 효과가 있는 것은 없습니다.잠깐만요, 험한 길이에요.
void setupView() {
final ViewPager.SimpleOnPageChangeListener pageChangeListener = new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
currentPagePosition = position;
// Update the viewPager height for the current view
/*
Borrowed from https://github.com/rnevet/WCViewPager/blob/master/wcviewpager/src/main/java/nevet/me/wcviewpager/WrapContentViewPager.java
Gather the height of the "decor" views, since this height isn't included
when measuring each page's view height.
*/
int decorHeight = 0;
for (int i = 0; i < viewPager.getChildCount(); i++) {
View child = viewPager.getChildAt(i);
ViewPager.LayoutParams lp = (ViewPager.LayoutParams) child.getLayoutParams();
if (lp != null && lp.isDecor) {
int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK;
boolean consumeVertical = vgrav == Gravity.TOP || vgrav == Gravity.BOTTOM;
if (consumeVertical) {
decorHeight += child.getMeasuredHeight();
}
}
}
int newHeight = decorHeight;
switch (position) {
case PAGE_WITH_SHORT_AND_STATIC_CONTENT:
newHeight += measureViewHeight(thePageView1);
break;
case PAGE_TO_FILL_PARENT:
newHeight = ViewGroup.LayoutParams.MATCH_PARENT;
break;
case PAGE_TO_WRAP_CONTENT:
// newHeight = ViewGroup.LayoutParams.WRAP_CONTENT; // Works same as MATCH_PARENT because...reasons...
// newHeight += measureViewHeight(thePageView2); // Doesn't allow scrolling when sideways and height is clipped
/*
Only option that allows the ScrollView content to scroll fully.
Just doing this might be way too tall, especially on tablets.
(Will shrink it down below)
*/
newHeight = ViewGroup.LayoutParams.MATCH_PARENT;
break;
}
// Update the height
ViewGroup.LayoutParams layoutParams = viewPager.getLayoutParams();
layoutParams.height = newHeight;
viewPager.setLayoutParams(layoutParams);
if (position == PAGE_TO_WRAP_CONTENT) {
// This page should wrap content
// Measure height of the scrollview child
View scrollViewChild = ...; // (generally this is a LinearLayout)
int scrollViewChildHeight = scrollViewChild.getHeight(); // full height (even portion which can't be shown)
// ^ doesn't need measureViewHeight() because... reasons...
if (viewPager.getHeight() > scrollViewChildHeight) { // View pager too tall?
// Wrap view pager height down to child height
newHeight = scrollViewChildHeight + decorHeight;
ViewGroup.LayoutParams layoutParams2 = viewPager.getLayoutParams();
layoutParams2.height = newHeight;
viewPager.setLayoutParams(layoutParams2);
}
}
// Bonus goodies :)
// Show or hide the keyboard as appropriate. (Some pages have EditTexts, some don't)
switch (position) {
// This case takes a little bit more aggressive code than usual
if (position needs keyboard shown){
showKeyboardForEditText();
} else if {
hideKeyboard();
}
}
}
};
viewPager.addOnPageChangeListener(pageChangeListener);
viewPager.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
// http://stackoverflow.com/a/4406090/4176104
// Do things which require the views to have their height populated here
pageChangeListener.onPageSelected(currentPagePosition); // fix the height of the first page
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
viewPager.getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
viewPager.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
}
}
);
}
...
private void showKeyboardForEditText() {
// Make the keyboard appear.
getDialog().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
inputViewToFocus.requestFocus();
// http://stackoverflow.com/a/5617130/4176104
InputMethodManager inputMethodManager =
(InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.toggleSoftInputFromWindow(
inputViewToFocus.getApplicationWindowToken(),
InputMethodManager.SHOW_IMPLICIT, 0);
}
...
/**
* Hide the keyboard - http://stackoverflow.com/a/8785471
*/
private void hideKeyboard() {
InputMethodManager inputManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
inputManager.hideSoftInputFromWindow(inputBibleBookStart.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
...
//https://github.com/rnevet/WCViewPager/blob/master/wcviewpager/src/main/java/nevet/me/wcviewpager/WrapContentViewPager.java
private int measureViewHeight(View view) {
view.measure(ViewGroup.getChildMeasureSpec(-1, -1, view.getLayoutParams().width), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
return view.getMeasuredHeight();
}
뷰를 측정하고 장식 높이를 측정하는 코드에 대해 @Raanan에게 감사드립니다.그의 라이브러리에 문제가 생겼습니다. 애니메이션이 더듬거렸고 대화 상자의 높이가 필요할 정도로 짧으면 ScrollView가 스크롤되지 않는 것 같습니다.
모든 대답이 완벽하게 작동하는 것은 아닙니다.그래서 제가 만들었어요.는 새로운 하여 새운페만때들하레요청을다합니이웃아클서를 만들 때 입니다.viewPager
의 높이는 현재 하위 보기의 높이입니다.
class WrapContentViewPager : ViewPager {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
private var curPos = 0
init {
addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
override fun onPageScrollStateChanged(state: Int) {}
override fun onPageScrolled(
position: Int,
positionOffset: Float,
positionOffsetPixels: Int
) {}
override fun onPageSelected(position: Int) {
curPos = position
requestLayout()
}
})
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
if (childCount == 0) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
return
}
measureChildren(widthMeasureSpec, heightMeasureSpec)
setMeasuredDimension(measuredWidth, getChildAt(curPos).measuredHeight)
}
}
ViewPager2가 모든 페이지의 최대 높이와 동일한 높이를 갖는 ViewPager2 솔루션을 원하는 사용자를 위해 안타깝게도 다음 해결 방법만 발견했습니다.
viewPager.doOnPreDraw {
//workaround to set the viewPagerheight the same as its children
var height = 0
for (i in 0 until featuresViewPager.adapter!!.itemCount) {
val viewHolder = viewPager.adapter!!.createViewHolder(viewPager, 0)
viewPager.adapter!!.bindViewHolder(viewHolder, i)
val child: View = viewHolder.itemView
child.layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT
val widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(viewPager.width, View.MeasureSpec.EXACTLY)
val heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
child.measure(widthMeasureSpec, heightMeasureSpec)
val childHeight = child.measuredHeight
child.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
if (childHeight > height)
height = childHeight
}
viewPager.layoutParams.height = height
}
저는 "슬프게"라고 말합니다. 왜냐하면 그것은 모든 페이지를 훑어보고, 그들의 관점을 만들고, 그것들을 측정하고, 그것이 다른 목적을 위한 기능을 호출하는 방식이기 때문입니다.
대부분의 경우 잘 작동합니다.
더 좋은 해결책이 있으면 알려주세요.
제 에는 나의경추가우가를 합니다.clipToPadding
문제를 해결했습니다.
<android.support.v4.view.ViewPager
...
android:clipToPadding="false"
...
/>
건배!
언급URL : https://stackoverflow.com/questions/8394681/android-i-am-unable-to-have-viewpager-wrap-content
'programing' 카테고리의 다른 글
Ajax 사용 방법.성공 시 및 실패 시 양식 시작? (0) | 2023.07.31 |
---|---|
PHP에서 IP 주소가 두 개의 IP 범위 내에 있는지 확인하는 방법은 무엇입니까? (0) | 2023.07.31 |
UI WebView의 모든 쿠키를 삭제하는 방법은 무엇입니까? (0) | 2023.07.31 |
ORA-01403: Select to에 대한 데이터를 찾을 수 없습니다. (0) | 2023.07.31 |
SQL 테이블 이름에 숫자를 포함하는 것이 좋습니까, 나쁘습니까? (0) | 2023.07.31 |