ViewPager가 콘텐츠를 다시 그리지 않고 그대로 유지 / 비어 있음
여기 ViewPager와 관련하여 매우 이상한 문제가 있습니다. 각 ViewPager 페이지에 목록을 포함하고 목록 데이터를 업데이트 할 때 목록 어댑터와 뷰 페이저 어댑터 모두에서 notifyDataSetChanged를 트리거합니다.
우리가 관찰 한 것은 때때로 페이지가 뷰 트리를 업데이트하지 않는다는 것입니다. 즉, 빈 상태로 유지되거나 페이지를 페이징 할 때 사라지는 경우도 있습니다. 몇 번 앞뒤로 페이징하면 콘텐츠가 갑자기 다시 나타납니다. Android에보기 업데이트가 누락 된 것 같습니다. 또한 계층 뷰어로 디버깅 할 때 뷰를 선택하면 뷰가 항상 다시 나타납니다. 계층 뷰어가 선택한 뷰를 강제로 다시 그리도록하기 때문입니다.
그래도이 작업을 프로그래밍 방식으로 만들 수는 없습니다. 목록보기 또는 전체보기 호출기를 무효화해도 효과가 없습니다.
이것은 compatibility-v4_r7 라이브러리입니다. 또한 뷰 페이저와 관련된 많은 문제를 해결한다고 주장하기 때문에 최신 개정판을 사용하려고 시도했지만 문제가 더 악화되었습니다 (예를 들어, 모든 페이지를 더 이상 페이지를 넘길 수 없도록 제스처가 깨졌습니다.).
다른 사람도 이러한 문제를 겪고 있습니까? 아니면 원인이 무엇인지 알고 있습니까?
마침내 해결책을 찾았습니다. 분명히 우리의 구현에는 두 가지 문제가 있습니다.
- 어댑터가에서보기를 제거하지 않았습니다
destroyItem()
. - 뷰를 캐싱하여 레이아웃을 한 번만 확장해야했고에서 뷰를 제거하지 않았기 때문에 뷰를
destroyItem()
추가하지 않고instantiateItem()
현재 위치에 해당하는 캐시 된 뷰를 반환했습니다.
나는 소스 코드를 너무 깊이 들여다 보지 않았고 ViewPager
-당신이 그렇게해야한다는 것이 명확하지 않지만 문서는 다음과 같이 말합니다.
destroyItem ()
주어진 위치에 대한 페이지를 제거합니다. 어댑터는 해당 컨테이너에서 뷰를 제거해야하지만 finishUpdate (ViewGroup)에서 반환 될 때까지이 작업이 수행되도록해야합니다.
과:
매우 간단한 PagerAdapter는 페이지 뷰 자체를 키 개체로 사용하도록 선택할 수 있으며, 생성 후 instantiateItem (ViewGroup, int)에서 반환하고 부모 ViewGroup에 추가 할 수 있습니다. 일치하는 destroyItem (ViewGroup, int, Object) 구현은 상위 ViewGroup에서 View를 제거하고 isViewFromObject (View, Object)는 return view == object;로 구현 될 수 있습니다.
내 결론은 그래서 ViewPager
명시 적으로 추가 /에서 아이를 제거하기 위해 기본 어댑터에 의존 instantiateItem()
/ destroyItem()
. 즉, 어댑터가의 하위 클래스 인 PagerAdapter
경우 하위 클래스는이 논리를 구현해야합니다.
참고 : 내부 목록을 사용 하는 경우이 점에 유의하세요 ViewPager
.
이 경우 ViewPager
기호가있는 조각 내부 설정 FragmentPagerAdapter
, 사용하는 getChildFragmentManager()
대신에 getSupportFragmentManager()
당신의 초기화 매개 변수로 FragmentPagerAdapter
.
mAdapter = new MyFragmentPagerAdapter(getChildFragmentManager());
대신에
mAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager());
나는 똑같은 문제가 있었지만 실제로 destroyItem에서 뷰를 파괴했습니다 (생각했습니다). 그러나 문제는 내가 viewPager.removeViewAt(index);
insted ofviewPager.removeView((View) object);
잘못된:
@Override
public void destroyItem(ViewGroup viewPager, int position, Object object) {
viewPager.removeViewAt(position);
}
권리:
@Override
public void destroyItem(ViewGroup viewPager, int position, Object object) {
viewPager.removeView((View) object);
}
ViewPager는 항목 재사용과 관련하여 현명한 작업을 시도하지만 변경된 경우 새 항목 위치를 반환해야합니다. PagerAdapter에 다음을 추가해보십시오.
public int getItemPosition (Object object) { return POSITION_NONE; }
기본적으로 ViewPager에 모든 것이 변경되었음을 알리고 모든 것을 다시 인스턴스화하도록합니다. 그게 내 머리 위에서 생각할 수있는 유일한 것입니다.
Android 지원 라이브러리에는 모든 페이지에 ListView가있는 ViewPager가 포함 된 데모 활동이 있습니다. 당신은 아마 그것을보고 그것이 무엇을하는지보아야 할 것입니다.
Eclipse에서 (Android Dev Tools r20 사용) :
- 고르다
New > Android Sample Project
- 대상 API 레벨을 선택하십시오 (사용 가능한 최신 API를 제안합니다).
- 고르다
Support4Demos
- 프로젝트를 마우스 오른쪽 버튼으로 클릭하고
Android Tools > Add Support Library
- 앱을 실행하고 선택
Fragment
후Pager
이에 대한 코드는 src/com.example.android.supportv4.app/FragmentPagerSupport.java
. 행운을 빕니다!
I ran into this and had very similar issues. I even asked it on stack overflow.
For me, in the parent of the parent of my view someone subclassed LinearLayout
and overrode requestLayout()
without calling super.requestLayout()
. This prevented onMeasure
and onLayout
from being called on my ViewPager (although hierarchyviewer manually calls these). Without being measured they'll show up as blank in ViewPager.
So check your containing views. Make sure they subclass from View and don't blindly override requestLayout or anything similar.
Had the same issue, which is something to do with ListView
(because my empty view shows up fine if the list is empty). I just called requestLayout()
on the problematic ListView
. Now it draws fine!
I ran into this same problem when using a ViewPager and FragmentStatePagerAdapter. I tried using a handler with a 3 second delay to call invalidate() and requestLayout() but it didn't work. What did work was resetting the viewPager's background color as follows:
MyFragment.java
private Handler mHandler;
private Runnable mBugUpdater;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = new ViewPager(getActivity());
//...Create your adapter and set it here...
mHandler = new Handler();
mBugUpdater = new Runnable(){
@Override
public void run() {
mVp.setBackgroundColor(mItem.getBackgroundColor());
mHandler = null;
mBugUpdater = null;
}
};
mHandler.postDelayed(mBugUpdater,50);
return rootView;
}
@Override
public void onPause() {
if(mHandler != null){
//Remove the callback if it hasn't triggered yet
mHandler.removeCallbacks(mBugUpdater);
mHandler = null;
mBugUpdater = null;
}
super.onPause();
}
I had a problem with the same symptoms, but a different cause that turned out to be a silly mistake on my part. Thought I'd add it here in case it helps anyone.
I had a ViewPager using FragmentStatePagerAdapter which used to have two fragments, but I later added a third. However, I forgot that the default off screen page limit is 1 -- so, when I'd switch to the new third fragment, the first one would get destroyed, then recreated after switching back. The problem was that my activity was in charge of notifying these fragments to initialize their UI state. This happened to work when the activity and fragment lifecycles were the same, but to fix it I had to change the fragments to initialize their own UI during their startup lifecycle. In the end I also wound up changing setOffscreenPageLimit to 2 so that all three fragments were kept alive at all times (safe in this case since they were not very memory intensive).
Tried too many solutions but unexpectedly viewPager.post()
worked
mAdapter = new NewsVPAdapter(getContext(), articles);
viewPager.post(new Runnable() {
@Override
public void run() {
viewPager.setAdapter(mAdapter);
}
});
I had similar issue. I cache views because I need only 3 views in ViewPager
. When I slide forward everything is okay but when I start to slide backward occurs error, it says that "my view already has a parent". The solution is to delete unneeded items manually.
@Override
public Object instantiateItem(ViewGroup container, int position) {
int localPos = position % SIZE;
TouchImageView view;
if (touchImageViews[localPos] != null) {
view = touchImageViews[localPos];
} else {
view = new TouchImageView(container.getContext());
view.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
touchImageViews[localPos] = view;
}
view.setImageDrawable(mDataModel.getPhoto(position));
Log.i(IRViewPagerAdpt.class.toString(), "Add view " + view.toString() + " at pos: " + position + " " + localPos);
if (view.getParent() == null) {
((ViewPager) container).addView(view);
}
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object view) {
// ((ViewPager) container).removeView((View) view);
Log.i(IRViewPagerAdpt.class.toString(), "remove view " + view.toString() + " at pos: " + position);
}
..................
private static final int SIZE = 3;
private TouchImageView[] touchImageViews = new TouchImageView[SIZE];
For me the problem was coming back to the activity after the app process was killed. I am using a custom view pager adapter modified from the Android sources.The view pager is embedded directly in the activity.
Calling viewPager.setCurrentItem(position, true);
(with animation) after setting the data and notifyDataSetChanged() seems to work, but if the parameter is set to false it doesn't and the fragment is blank. This is an edge case which may be of help to someone.
참고URL : https://stackoverflow.com/questions/11736953/viewpager-does-not-redraw-content-remains-turns-blank
'code' 카테고리의 다른 글
Java의 "코드가 너무 큼"컴파일 오류 (0) | 2020.09.19 |
---|---|
목록을 집합으로 변환하면 요소 순서가 변경됩니다. (0) | 2020.09.19 |
Maven이 로컬 아티팩트를 찾지 못함 (0) | 2020.09.19 |
인스턴스를 시작할 때 ECU 유닛, CPU 코어 및 메모리는 무엇을 의미합니까? (0) | 2020.09.19 |
mocha before ()의 비동기 함수는 it () 사양 전에 항상 완료됩니까? (0) | 2020.09.19 |