【发布时间】:2014-08-09 03:39:48
【问题描述】:
在我的应用程序中,目前有一个部分包含一个片段,该片段可以查询数据库以获取对象列表,然后显示它们(使用 ListView)。
当用户单击列表中的一个对象时,该部分的高度会变大以合并.replace()s ListView 片段并向上移动的不同片段。
这个新片段显示与用户单击的对象相关的信息。
这个片段中的一个视图是一个ViewPager,它只包含2个片段(最多):
- 一个计时器片段。
- 日历片段。
计时器片段是一个片段,它仅使用CountDownTimer 并更改TextView 的文本onTick()。此片段可能会显示也可能不会显示,具体取决于对象。
但是,日历片段包含一个更重的视图 - 自定义日历视图。
日历应该显示当前日期(现在)之前和之后一年中的日子。
日历片段(实际上是视图,因为片段中没有根本逻辑)导致当用户单击对象时触发的动画卡顿并且看起来很糟糕。这仅在第一次单击对象时发生。第二次更流畅了(我想这要归功于ViewPager保存了片段的状态,但我不确定......)。
我想知道代码中是否存在任何特定的瓶颈/问题会导致它的行为如此。我最好的猜测是一起加载的视图太多了。
我想到的第一个解决方案,基本上是在片段内移动动画,并在片段完全加载并准备好显示后触发它。然而,这意味着我将从片段本身内部控制父级(片段的容器)......不确定这是否是一个好的设计。不过,我可以为此创建一个侦听器,并将其调用放在onCreateView() 的末尾。
另一种可能的解决方案,这只是我的一个理论,但是在单独的线程上创建所有视图,然后将它们添加到主线程中的 UI 可能会稍微加快进程。虽然,我不确定这会多好(在性能方面),如果有的话,以及这是一种好的做法。
如何优化我的CalendarView(或者我的整个“对象视图片段”)以使动画正常工作?
CalendarView 包括:
- 一个垂直的
LinearLayout,包含2个子视图:- 顶栏是
TableLayout,其中包含7 天的名称。 - 一个
GridView,其中填充了TextViews 天数。
- 顶栏是
一些代码:
MainActivity - 替换当前片段
@Override
public void OnGoalSelected(Parcelable goal) {
Log.i(TAG, "GoalSelected");
isMinimized = false;
HabitGoalViewFragment newFragment = new HabitGoalViewFragment();
Bundle args = new Bundle();
args.putParcelable(GOAL_POSITION_KEY, goal);
newFragment.setArguments(args);
getSupportFragmentManager().addOnBackStackChangedListener(this);
getSupportFragmentManager().beginTransaction()
.setCustomAnimations(R.anim.fadein, R.anim.fadeout, R.anim.fadein, R.anim.fadeout)
.replace(R.id.cardFragmentContainer, newFragment)
.addToBackStack(null)
.commit();
mActionBar.setCustomView(R.layout.ab_goal_view);
mLL.getLayoutParams().height += screenHeight;
ObjectAnimator objAnim = ObjectAnimator.ofFloat(mLL, "translationY", AmountToMove).setDuration(500);
objAnim.setInterpolator(new DecelerateInterpolator());
objAnim.start();
}
习惯目标视图
public static Class<?>[] mFragmentArray = {
HabitCalendarFragment.class,
HabitDurationTimerFragment.class
};
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_goal_view, container, false);
mActionBar = getActivity().getActionBar();
mActionBar.getCustomView().findViewById(R.id.goal_view_back_button_parent).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getActivity().getSupportFragmentManager().popBackStackImmediate();
}
});
mHabitGoal = getArguments().getParcelable(MainActivity.GOAL_POSITION_KEY);
............
mViewPager = (ViewPager) view.findViewById(R.id.pager);
mViewPager.setAdapter(new ViewPagerAdapter(getActivity().getSupportFragmentManager(), getActivity()));
return view;
}
private class ViewPagerAdapter extends FragmentStatePagerAdapter {
private Context mContext;
public ViewPagerAdapter(FragmentManager fm, Context context) {
super(fm);
mContext = context;
}
@Override
public Fragment getItem(int position) {
return Fragment.instantiate(mContext, mFragmentArray[position].getName());
}
@Override
public int getCount() {
return mFragmentArray.length;
}
}
CalendarView(这是View本身,而不是fragment!)
public class CalendarView extends LinearLayout {
private final String TAG = this.getClass().getName();
private Context mContext;
private TableLayout mTopBarTableLayout;
private TableRow mTableRow;
public CalendarView(Context context) {
super(context);
mContext = context;
this.setOrientation(VERTICAL);
mTopBarTableLayout = new TableLayout(mContext);
mTopBarLinearLayout.setStretchAllColumns(true);
mTableRow = new TableRow(mContext);
int[] mDaysList = {R.string.days_sunday, R.string.days_monday, R.string.days_tuesday,
R.string.days_wednesday, R.string.days_thursday, R.string.days_friday, R.string.days_saturday}; //
AutoScrollingTextView mDayTextView;
int padding;
for (int i = 0; i < 7; i++) {
mDayTextView= new AutoScrollingTextView(mContext);
padding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8, getResources().getDisplayMetrics());
mDayTextView.setPadding(padding, padding, padding, padding);
mDayTextView.setTextSize(16);
mDayTextView.setGravity(Gravity.CENTER);
mDayTextView.setText(getResources().getString(mDaysList[j]).substring(0, 3).toUpperCase(Locale.US));
mDayTextView.setWidth(0);
mDayTextView.setSingleLine(true);
mDayTextView.setHorizontallyScrolling(true);
mDayTextView.setEllipsize(TextUtils.TruncateAt.MARQUEE);
mTableRow.addView(mDayTextView, i);
}
mTopBarLinearLayout.addView(mTableRow, 0);
this.addView(mTopBarLinearLayout, 0);
this.addView(new CalendarGridView(mContext), 1);
}
private class CalendarGridView extends GridView {
Context mContext;
DateTime CurrentMonthDateTime, NextYearDT, LastYearDT;
int offset;
public CalendarGridView(Context context) {
super(context);
mContext = context;
init();
}
public CalendarGridView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
init();
}
public CalendarGridView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mContext = context;
init();
}
public void init() {
this.setNumColumns(7); // 7 columns - 1 for each day
this.setStretchMode(STRETCH_COLUMN_WIDTH);
this.setAdapter(new CalendarAdapter());
CurrentMonthDateTime = DateTime.now();
LastYearDT = DateTime.now().minusYears(1).withDayOfMonth(1);
offset = LastYearDT.getDayOfWeek();
if (offset == 7)
offset = 0;
int n = Days.daysBetween(LastYearDT.withTimeAtStartOfDay(), CurrentMonthDateTime.withTimeAtStartOfDay()).getDays() + offset;
Log.i(TAG, "Days Offset = " + n);
this.setSelection(n);
}
private class CalendarAdapter extends BaseAdapter {
private int offset, n;
private DateTime mDateTime, mDateToPrint;
public CalendarAdapter() {
mDateTime = DateTime.now().minusYears(1).withDayOfMonth(1);
NextYearDT = DateTime.now().plusYears(1).withDayOfMonth(1);
n = Days.daysBetween(mDateTime.withTimeAtStartOfDay(),
NextYearDT.withTimeAtStartOfDay()).getDays();
// round up to the nearest number divisible by 7
n += (7 - n%7);
offset = mDateTime.getDayOfWeek(); // 1 - mon, 2 - tue ... 7 - sun
// set first day to Sunday
if (offset == 7)
offset = 0;
mDateTime = mDateTime.minusDays(offset);
}
@Override
public int getCount() {
return n;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
SquareTextView view = (SquareTextView) convertView;
if (convertView == null) {
view = new SquareTextView(mContext);
view.setTextSize(18);
view.setGravity(Gravity.CENTER);
view.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Log.i(TAG, ((SquareTextView) v).getText().toString());
}
});
} else {
view.setBackgroundResource(0); // TODO set as drawable and then remove it
view.setTag(null);
}
mDateToPrint = mDateTime.plusDays(position);
if (mDateToPrint.getDayOfMonth() == 1)
view.setTag(mDateToPrint.monthOfYear().getAsShortText(Locale.ENGLISH));
view.setText(mDateToPrint.getDayOfMonth() + "");
if (mDateToPrint.withTimeAtStartOfDay().isEqual(CurrentMonthDateTime.withTimeAtStartOfDay())) {
//view.setBackgroundResource(R.color.background_gray);
view.setBackgroundColor(getResources().getColor(R.color.green));
view.setTag("today");
}
return view;
}
}
}
}
【问题讨论】:
-
问题是,当您只需要几个视图时,您创建的视图谁知道有多少。实现一个视图模式以提高效率。
-
@bbaker,不过,我正在回收视图。此外,日历中的每个视图都是
TextView,因此不需要视图持有者,因为我猜没有任何子视图。感谢您的评论! -
@xTCx 你能试试吗? => 以短暂的延迟触发
ObjectAnimator- 比如500ms。将ObjectAnimator声明为final。创建一个Handler并将调用objAnim.start()放在Runnable中。将Runnable发布到mHandler.postDelayed(mRunnable, 500L);。这样更好吗?在调用动画之前,片段(或视图)可能没有足够的时间进行初始化。如果延迟发布确实起作用,您可以在第一个事务中使用它,然后让 ViewPager 处理后续检索。
标签: android performance listview android-fragments calendar