膨胀视图并将它们添加到Horizo​​ntalScrollView中的LinearLayout - 奇怪的行为

时间:2011-01-12 22:50:11

标签: android

我正在尝试创建一个可以添加到布局文件的类,设置适配器,然后从DataSetObserver进行更新。

在Nexus One上,这似乎工作得很好,但是在G1上我得到了一些奇怪的行为。

因此活动的布局文件是:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="vertical" android:layout_width="fill_parent"
 android:layout_height="fill_parent">

 <include android:layout_width="fill_parent"
  android:layout_height="wrap_content" android:id="@+id/ActionBarInclude"
  layout="@layout/action_bar"></include>

  <LinearLayout android:layout_width="fill_parent"
   android:layout_height="fill_parent" android:orientation="vertical"
   android:background="@drawable/action_bar_drop_shadow">

   <TextView android:layout_height="wrap_content"
    android:layout_width="fill_parent" android:gravity="center"
    android:id="@+id/AccountSummaryAppTitleTextView" android:text=""
    style="@style/titleTextView"></TextView>

   <co.uk.gauntface.android.admob.views.TabBarScrollView
    android:id="@+id/AccountSummaryTabBarScrollView"
    android:layout_width="fill_parent" android:layout_height="wrap_content"
    android:scrollbars="none">

   </co.uk.gauntface.android.admob.views.TabBarScrollView>

   <co.uk.gauntface.android.admob.views.SlidingLayout android:layout_width="fill_parent"
    android:id="@+id/AccountSummarySlidingLayout" android:layout_weight="1"
    android:layout_height="wrap_content" android:scrollbars="none" android:fadingEdge="none"
    android:fillViewport="true">
            </co.uk.gauntface.android.admob.views.SlidingLayout>

  </LinearLayout>

</LinearLayout>

现在我将FillViewPort设置为true的原因是因为类似的问题:LinearLayout not expanding inside a ScrollView 虽然这没有解决我的问题。

活动的源代码是:

package co.uk.gauntface.android.admob;

import java.util.ArrayList;
import co.uk.gauntface.android.admob.models.RawSite;
import co.uk.gauntface.android.admob.models.SiteStat;
import co.uk.gauntface.android.admob.networking.AdmobDownloadListener;
import co.uk.gauntface.android.admob.networking.SiteStatService;
import co.uk.gauntface.android.admob.views.AccountSummaryAdapter;
import co.uk.gauntface.android.admob.views.SlidingLayout;
import co.uk.gauntface.android.admob.views.TabBarScrollView;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

public class AccountSummary extends AdmobActivity
{ 
 private final static String TAG = "admob";

 public static final String ACCOUNT_SUMMARY_INTENT_EXTRA_ID = "AccountSummaryIntentExtraID";

 private String mAccountID;
 private RawSite mRawSiteData;

 private Handler mHandler;
 private SiteStatService mSiteStatService;
 private ArrayList<SiteStat> mSiteStatData;

 private ActionBarHelper mActionBarHelper;

 private TextView mAppTitleTextView;
 private TabBarScrollView mTabBarScrollView;
 private SlidingLayout mSlidingLayout;
 private AccountSummaryAdapter mAdapter;

 /** Called when the activity is first created. */
 public void onCreate(Bundle savedInstanceState)
 {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.account_summary);

  mAccountID = getIntent().getExtras().getString(ACCOUNT_SUMMARY_INTENT_EXTRA_ID);
  mSiteStatService = new SiteStatService(getApplicationContext());
  //mChartAdapter = new PointPositionAdapter(getApplicationContext());

  initActivity();

  setUpUI();

  if(getLastNonConfigurationInstance() != null) {
   mSiteStatData = (ArrayList<SiteStat>) getLastNonConfigurationInstance();
   mAdapter.setSiteStatData(mSiteStatData);
  } else {
   updateSiteStatData();
  }
 }

 /**public void onConfigurationChanged (Configuration newConfig) {
  super.onConfigurationChanged(newConfig);
  setContentView(R.layout.account_summary);

  setUpUI();
 }**/

 @Override
 public Object onRetainNonConfigurationInstance() {
  return mSiteStatData;
 }

 private void initActivity() {
  mHandler = new Handler() {
   public void handleMessage(Message msg) {
    switch(msg.arg1) {
    default:
     break;
    }
   }
  };

  mAdapter = new AccountSummaryAdapter(getApplicationContext(), new Integer[]{
   R.string.revenue,
   R.string.ecpm,
   R.string.requests,
   R.string.impressions,
   R.string.fill_rate,
   R.string.ctr
  });

  DatabaseManager dbManager = new DatabaseManager(getApplicationContext());
  dbManager.open();
  mRawSiteData = dbManager.getSite(mAccountID);
  dbManager.close();

 }

 private void setUpUI() {
  mActionBarHelper = new ActionBarHelper(this);

  mAppTitleTextView = (TextView) findViewById(R.id.AccountSummaryAppTitleTextView);
  mAppTitleTextView.setText(mRawSiteData.getSiteName());

  mTabBarScrollView = (TabBarScrollView) findViewById(R.id.AccountSummaryTabBarScrollView);
  mTabBarScrollView.setAdapter(mAdapter.getTabBarAdapter());
  mTabBarScrollView.setOnItemOnClickListener(mAdapter);

  mSlidingLayout = (SlidingLayout) findViewById(R.id.AccountSummarySlidingLayout);
  mSlidingLayout.setAdapter(mAdapter.getSlidingLayoutAdapter());
  mSlidingLayout.setOnDisplayChangeListener(mAdapter);
 }

 private void updateSiteStatData() {
  mActionBarHelper.incrementRequests();
  int daysToGet = getResources().getInteger(R.integer.account_summary_days);
  mSiteStatService.downloadDailySiteStats(daysToGet, mRawSiteData.getSiteID(), new AdmobDownloadListener() {

   public void onDownloadSuccess(Object obj) {
    mActionBarHelper.decrementRequests();
    mSiteStatData = (ArrayList<SiteStat>) obj;

    //mAdapter.setSiteStatData(mSiteStatData);
   }

   public void onDownloadError(int errorCode, String errorMsg) {
    mActionBarHelper.decrementRequests();
    displayErrorMessage(errorCode, errorMsg);
   }
  });
 }

 public void onClick(View v) {
  switch(v.getId())
  {
  case R.id.ActionBarRefreshImageButton:
   updateSiteStatData();
   break;
  }
 }
}

这将显示视图正常,但SlidingLayout实际上将显示为空白(即它不会膨胀LinearLayout中包含的视图。

SlidingLayout的源代码是:

package co.uk.gauntface.android.admob.views;

import co.uk.gauntface.android.admob.R;
import android.content.Context;
import android.database.DataSetObserver;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.Adapter;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;

public class SlidingLayout extends HorizontalScrollView {

 private static final String TAG = "admob";

 private int mSelectedPosition;
 private int mNewSelectedPosition;
 private LinearLayout mContainerLinearLayout;

 private int mScaledTouchSlop;

 private float mPrevX;

 private int mItemCount;
 private boolean mIsTouchEventScroll;

 private SlidingLayoutAdapter mAdapter;
 private DataSetObserver mDataSetObserver;
 private OnDisplayChangeListener mDisplayChangeListener;

 public SlidingLayout(Context context) {
  super(context);

  constructor();
 }

 public SlidingLayout(Context context, AttributeSet attrs) {
  super(context, attrs);

  constructor();
 }

 public SlidingLayout(Context context, AttributeSet attrs, int defStyle) {
  super(context, attrs, defStyle);

  constructor();
 }

 private void constructor() {
  Log.v(TAG, "SlidingLayout: constructor()");
  mSelectedPosition = 0;
  mNewSelectedPosition = 0;

  mItemCount = 0;

  mScaledTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
 }

 @Override
 public boolean onTouchEvent(MotionEvent event) {
  Log.v(TAG, "SlidingLayout: onTouchEvent()");
  int action = event.getAction();

  switch (action) {
  case MotionEvent.ACTION_DOWN:
   break;
  case MotionEvent.ACTION_MOVE:
   int deltaX = (int) (mPrevX - event.getX());
   scrollBy(deltaX, 0);
   break;
  case MotionEvent.ACTION_UP:
   animateToPosition();
  }

  mPrevX = event.getX();

  return true;
 }

 private void animateToPosition() {
  Log.v(TAG, "SlidingLayout: animateToPosition()");
  double scrollX = getScrollX();
  int screenWidth = getWidth();

  double ratio = scrollX / (double) screenWidth;
  int whichScreen = (int) Math.round(ratio);

  if(whichScreen >= 0 && whichScreen < mItemCount) {
   int newX = whichScreen * screenWidth;
   //int screenDiff = whichScreen - mDisplayedView;
   int screenDiff = whichScreen - mSelectedPosition;
   switch(screenDiff) {
   case -1:
    mNewSelectedPosition = mSelectedPosition - 1;
    break;
   case 0:
    mNewSelectedPosition = mSelectedPosition;
    break;
   case 1:
    mNewSelectedPosition = mSelectedPosition + 1;
    break;
   }

   if(mNewSelectedPosition < 0) {
    mNewSelectedPosition = 0;
   } else if(mNewSelectedPosition >= mItemCount) {
    mNewSelectedPosition = mItemCount - 1;
   }

   mIsTouchEventScroll = true;
   smoothScrollTo(newX, 0);
  }
 }

 public void setOnDisplayChangeListener(OnDisplayChangeListener changeListener) {
  mDisplayChangeListener = changeListener;
 }

 public void setAdapter(SlidingLayoutAdapter adapter) {
  Log.v(TAG, "SlidingLayout: setAdapter()");
  if(mContainerLinearLayout == null) {
   mContainerLinearLayout = new LinearLayout(getContext());
   mContainerLinearLayout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
   mContainerLinearLayout.setOrientation(LinearLayout.HORIZONTAL);
   mContainerLinearLayout.setBackgroundColor(getContext().getResources().getColor(R.color.admob_color));

   addView(mContainerLinearLayout);
  }

  if(mAdapter != null) {
   mAdapter.unregisterDataSetObserver(mDataSetObserver);
  }

  mAdapter = adapter;

  if(mAdapter != null) {
   mDataSetObserver = new SlidingLayoutDataSetObserver();
   mAdapter.registerDataSetObserver(mDataSetObserver);

   mItemCount = mAdapter.getCount();
   mSelectedPosition = mAdapter.getSelectedPosition();
  } else {
   mItemCount = 0;
   mSelectedPosition = 0;

   return;
  }

  populateLayout();
 }

 // l is horizontal scroll origin, t is vertical
 /**protected void onScrollChanged (int l, int t, int oldl, int oldt) {
  super.onScrollChanged(l, t, oldl, oldt);
  if(mIsTouchEventScroll) {
   if(l % getWidth() == 0) {
    mIsTouchEventScroll = false;
    mSelectedPosition = mNewSelectedPosition;
    if(mDisplayChangeListener != null) {
     mDisplayChangeListener.onDisplayChange(l/getWidth());
    }
   }
  }
 }**/

 private void populateLayout() {
  Log.v(TAG, "SlidingLayout: populateLayout() - itemCount = "+mItemCount);
  if(mContainerLinearLayout != null) {
   mContainerLinearLayout.removeAllViews();
  }

  for(int i = 0; i < mItemCount; i++) {
   View v = mAdapter.getView(i, null, null);
   v.setMinimumWidth(getWidth());
   mContainerLinearLayout.addView(v);
  }

  invalidate();

  scrollTo(mSelectedPosition * getWidth(), 0);

  //View childView = mContainerLinearLayout.getChildAt(mSelectedPosition);
  //mContainerLinearLayout.invalidate();
  //childView.invalidate();
  Log.v(TAG, "SlidingLayout: populateLayout() scrollX - "+getScrollX());
  //Log.v(TAG, "SlidingLayout: populateLayout() childView.width() - "+childView.getWidth());
  Log.v(TAG, "SlidingLayout: populateLayout() getWidth() - "+getWidth());
  Log.v(TAG, "SlidingLayout: populateLayout() getHeight() - "+getHeight());
  //Log.v(TAG, "SlidingLayout: populateLayout() container.getWidth() - "+mContainerLinearLayout.getWidth());
  //Log.v(TAG, "SlidingLayout: populateLayout() container.getHeight() - "+mContainerLinearLayout.getHeight());
 }

 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  super.onSizeChanged(w, h, oldw, oldh);
  if(mAdapter != null) {
   mItemCount = mAdapter.getCount();
   mSelectedPosition = mAdapter.getSelectedPosition();
  }
  populateLayout();
 }

 public interface OnDisplayChangeListener {
  abstract void onDisplayChange(int position);
 }

 public interface SlidingLayoutAdapter extends Adapter {
  abstract int getSelectedPosition();
 }

 public class SlidingLayoutDataSetObserver extends DataSetObserver {
  public SlidingLayoutDataSetObserver() {
   super();
  }

  @Override
  public void onChanged() {
   Log.v(TAG, "SlidingLayout: onChanged()");
   mItemCount = mAdapter.getCount();
   mSelectedPosition = mAdapter.getSelectedPosition();
   populateLayout();
  }

  @Override
  public void onInvalidated() {
   // Data is invalid so we should reset our state
   //mItemCount = 0;
   //mSelectedPosition = 0;//mAdapter.getSelectedPosition();
   //Log.v(TAG, "SlidingLayout: onInvalidated() removeAllViews");
   //mContainerLinearLayout.removeAllViews();
   //invalidate();
   //populateLayout();
   //requestLayout();
   Log.v(TAG, "SlidingLayout: onInvalidated()");

   mItemCount = mAdapter.getCount();
   mSelectedPosition = mAdapter.getSelectedPosition();
   populateLayout();
  }
 }
}

现在实际发生的是LinearLayout(红色)填充整个视图,但是对LinearLayout上的getWidth()和getHeight()的任何调用都返回0(它本身就足够奇怪)。

但是如果我触摸一个单独的Horizo​​ntalScrollView(主活动中的mTabBarScrollView),SlidingLayout实际上会调整大小/重绘/布局。当Web服务使用数据更新适配器时也会发生同样的情况,调用notifyDataSetChanged()(导致调整大小/重绘/布局),但是在活动的onCreate方法中调用notifydatasetchanged()不会产生相同的效果。

登录android时没有出现任何错误。

我不知道它可以做什么/我可以做些什么来强制布局更新/膨胀。

非常欢迎任何想法/建议。

干杯, 马特

P.S。恭喜你,如果你在帖子中做到这一点:)

1 个答案:

答案 0 :(得分:0)

最后的解决方案是测量子视图并传入一个测量规范,强制它们是一个精确的宽度/高度:

v.measure(MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY));

原始代码可以在github上找到https://github.com/gauntface/SideSwipeSnapViewLibrary