我正在尝试创建一个可以添加到布局文件的类,设置适配器,然后从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(它本身就足够奇怪)。
但是如果我触摸一个单独的HorizontalScrollView(主活动中的mTabBarScrollView),SlidingLayout实际上会调整大小/重绘/布局。当Web服务使用数据更新适配器时也会发生同样的情况,调用notifyDataSetChanged()(导致调整大小/重绘/布局),但是在活动的onCreate方法中调用notifydatasetchanged()不会产生相同的效果。
登录android时没有出现任何错误。
我不知道它可以做什么/我可以做些什么来强制布局更新/膨胀。
非常欢迎任何想法/建议。
干杯, 马特
P.S。恭喜你,如果你在帖子中做到这一点:)
答案 0 :(得分:0)
最后的解决方案是测量子视图并传入一个测量规范,强制它们是一个精确的宽度/高度:
v.measure(MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY));
原始代码可以在github上找到https://github.com/gauntface/SideSwipeSnapViewLibrary