Android 动态高度寻呼机
我正在尝试在自定义滚动视图中创建一个自定义viewpager,动态地包装当前孩子的身高Android 动态高度寻呼机,android,android-viewpager,android-custom-view,android-scrollview,Android,Android Viewpager,Android Custom View,Android Scrollview,我正在尝试在自定义滚动视图中创建一个自定义viewpager,动态地包装当前孩子的身高 package com.example.vihaan.dynamicviewpager; import android.content.Context; import android.util.AttributeSet; import android.view.GestureDetector; import android.view.MotionEvent; import android.widget.Sc
package com.example.vihaan.dynamicviewpager;
import android.content.Context;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.widget.ScrollView;
/**
* Created by vihaan on 1/9/15.
*/
public class CustomScrollView extends ScrollView {
private GestureDetector mGestureDetector;
public CustomScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
mGestureDetector = new GestureDetector(context, new YScrollDetector());
setFadingEdgeLength(0);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return super.onInterceptTouchEvent(ev)
&& mGestureDetector.onTouchEvent(ev);
}
// Return false if we're scrolling in the x direction
class YScrollDetector extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
return (Math.abs(distanceY) > Math.abs(distanceX));
}
}
}
定制寻呼机
/**
* Created by vihaan on 1/9/15.
*/
public class CustomPager extends ViewPager {
public CustomPager (Context context) {
super(context);
}
public CustomPager (Context context, AttributeSet attrs) {
super(context, attrs);
}
@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);
int width = getMeasuredWidth();
int tabHeight = tab.getMeasuredHeight();
if (wrapHeight) {
// Keep the current measured width.
widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
}
int fragmentHeight = measureFragment(((Fragment) getAdapter().instantiateItem(this, getCurrentItem())).getView());
heightMeasureSpec = MeasureSpec.makeMeasureSpec(tabHeight + fragmentHeight + (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, getResources().getDisplayMetrics()), MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public int measureFragment(View view) {
if (view == null)
return 0;
view.measure(0, 0);
return view.getMeasuredHeight();
}
}
MyPagerAdapter
public class MyPagerAdapter extends FragmentPagerAdapter {
private List<Fragment> fragments;
public MyPagerAdapter(FragmentManager fm) {
super(fm);
this.fragments = new ArrayList<Fragment>();
fragments.add(new FirstFragment());
fragments.add(new SecondFragment());
fragments.add(new ThirdFragment());
fragments.add(new FourthFragment());
}
@Override
public Fragment getItem(int position) {
return fragments.get(position);
}
@Override
public int getCount() {
return fragments.size();
}
}
公共类MyPagerAdapter扩展了FragmentPagerAdapter{
私有列表片段;
公共MyPagerAdapter(碎片管理器fm){
超级(fm);
this.fragments=new ArrayList();
添加(新的FirstFragment());
添加(新的SecondFragment());
添加(新的ThirdFragment());
添加(新的第四个片段());
}
@凌驾
公共片段getItem(int位置){
返回碎片。获取(位置);
}
@凌驾
public int getCount(){
返回fragments.size();
}
}
我希望这能围绕目前的身高,但这只是考虑到第一个孩子的身高
github项目示例:在代码中做了一些调整,现在工作正常 1]
on测量
功能不正确。使用下面的逻辑
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mCurrentView == null) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
int height = 0;
mCurrentView.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
int h = mCurrentView.getMeasuredHeight();
if (h > height) height = h;
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
2] ViewPager
每次更改页面时都需要重新测量。执行此操作的好地方是setPrimaryItem
PagerAdapter的功能
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
super.setPrimaryItem(container, position, object);
if (position != mCurrentPosition) {
Fragment fragment = (Fragment) object;
CustomPager pager = (CustomPager) container;
if (fragment != null && fragment.getView() != null) {
mCurrentPosition = position;
pager.measureCurrentView(fragment.getView());
}
}
}
以下是指向GitHub项目的链接,其中包含以下调整:
@abhishek的ans会执行所需操作,但下面的代码也会在高度变化时添加动画
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);
}
}
公共类WrappingViewPager扩展了ViewPager{
私有布尔mAnimStarted=false;
公共包装视图管理器(上下文){
超级(上下文);
}
公共包装视图管理器(上下文、属性集属性){
超级(上下文,attrs);
}
@TargetApi(Build.VERSION\u code.JELLY\u BEAN)
@凌驾
测量时的保护空隙(内部宽度测量等级、内部高度测量等级){
超级测量(宽度测量、高度测量);
如果(!mAnimStarted&&null!=getAdapter()){
整数高度=0;
查看子项=((FragmentPagerAdapter)getAdapter()).getItem(getCurrentItem()).getView();
if(child!=null){
child.measure(widthmasurespec,MeasureSpec.makeMeasureSpec(0,MeasureSpec.unspected));
高度=child.getMeasuredHeight();
if(VersionUtils.isJellyBean()&&height=1){
getLayoutParams().height=targetHeight;
}否则{
int stepHeight=(int)(高度变化*插值时间);
getLayoutParams().height=currentHeight+stepHeight;
}
requestLayout();
}
@凌驾
公共布尔值willChangeBounds(){
返回true;
}
};
a、 setAnimationListener(新建Animation.AnimationListener(){
@凌驾
onAnimationStart上的公共无效(动画){
mAnimStarted=真;
}
@凌驾
onAnimationEnd上的公共无效(动画){
mAnimStarted=假;
}
@凌驾
onAnimationRepeat上的公共无效(动画){
}
});
a、 设定持续时间(1000);
startAnimation(a);
mAnimStarted=真;
}否则{
heightMeasureSpec=新高度;
}
}
超级测量(宽度测量、高度测量);
}
}
添加到@vihaan的解决方案中,如果您有一个PagerTitleStrip或PagetTabStrip,您可以添加此
// Account for pagerTitleStrip or pagerTabStrip
View tabStrip = getChildAt(0);
if (tabStrip instanceof PagerTitleStrip) {
tabStrip.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.UNSPECIFIED));
height += tabStrip.getMeasuredHeight();
}
在开始动画之前(在注释之前
// Not the best place to put this animation, but it works pretty good.
//不是放置动画的最佳位置,但效果相当不错。
这样就考虑了条带的高度。以防其他人像我一样找到这篇文章。没有bug的工作版本最初为零高度:
public class DynamicHeightViewPager extends ViewPager {
private View mCurrentView;
public DynamicHeightViewPager(Context context) {
super(context);
}
public DynamicHeightViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mCurrentView != null) {
mCurrentView.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
int height = Math.max(0, mCurrentView.getMeasuredHeight());
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
public void measureCurrentView(View currentView) {
mCurrentView = currentView;
requestLayout();
}
}
并用在定制的碎纸机上,像这样
public abstract class AutoheightFragmentPagerAdapter extends FragmentPagerAdapter {
private int mCurrentPosition = -1;
public AutoheightFragmentPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
super.setPrimaryItem(container, position, object);
if (position != mCurrentPosition && container instanceof DynamicHeightViewPager) {
Fragment fragment = (Fragment) object;
DynamicHeightViewPager pager = (DynamicHeightViewPager) container;
if (fragment != null && fragment.getView() != null) {
mCurrentPosition = position;
pager.measureCurrentView(fragment.getView());
}
}
}
}
这几行代码将解决这个问题 为viewpager类创建自定义小部件。在xml中,将其用于viewpager
public class DynamicHeightViewPager extends ViewPager {
private View mCurrentView;
public DynamicHeightViewPager(Context context) {
super(context);
}
public DynamicHeightViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mCurrentView != null) {
mCurrentView.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
int height = Math.max(0, mCurrentView.getMeasuredHeight());
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
public void measureCurrentView(View currentView) {
mCurrentView = currentView;
requestLayout();
}
}
然后在“查看寻呼机适配器”中重写下面的方法并添加代码
@Override
public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
super.setPrimaryItem(container, position, object);
if (container instanceof DynamicHeightViewPager) {
// instead of card view give your root view from your item.xml file.
CardView cardView = (CardView) object;
((DynamicHeightViewPager) container).measureCurrentView(cardView);
}
}
让你的浏览页面高度在xml文件中包装内容,这样你就可以检查结果了。这不是非常滞后/不平滑吗?至少对我来说是这样(在模拟器上)。@Timmiej93你可以在我的应用程序上实时查看。进入产品详细信息页面。它工作完美:)对不起,我可能(很可能)很愚蠢,但我在哪里可以找到你的应用程序?我可以从GitHub中获取它,但该版本中没有更改(据我所知)。编辑:你刚才添加的链接,我键入这个,谢谢!“产品详细信息页面”是指带有[规格-发货-付款-退货]的部分吗?如果是这样的话,那确实很顺利。我想我的是难以置信的滞后
public class DynamicHeightViewPager extends ViewPager {
private View mCurrentView;
public DynamicHeightViewPager(Context context) {
super(context);
}
public DynamicHeightViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mCurrentView != null) {
mCurrentView.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
int height = Math.max(0, mCurrentView.getMeasuredHeight());
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
public void measureCurrentView(View currentView) {
mCurrentView = currentView;
requestLayout();
}
}
@Override
public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
super.setPrimaryItem(container, position, object);
if (container instanceof DynamicHeightViewPager) {
// instead of card view give your root view from your item.xml file.
CardView cardView = (CardView) object;
((DynamicHeightViewPager) container).measureCurrentView(cardView);
}
}