Re-work the layout computation for MessageListItem
This now uses an XML layout that gets inflated and computed after a layout pass. The drawing simply uses the coordinates stored after the layout. This makes it a lot easier to maintain the different views and allows us to simply provide different XML files for different modes/views, isntead of trying to hand tweak Java layout code. Some TODOs - clean up the "paints" and optimize the layout/drawing computation Change-Id: I784919f726bd4d80aba8744a8f047fcfe79ad93a
This commit is contained in:
parent
058eb3984f
commit
8b2109f047
|
@ -0,0 +1,92 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2011 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<!-- This layout is used as a template to create a custom message item view
|
||||
in narrow mode. To be able to get the correct measurements, every source field should
|
||||
be populated with data here. E.g:
|
||||
- Text View should set text to a random long string (android:text="@string/long_string")
|
||||
- Image View should set source to a specific asset -->
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal">
|
||||
<ImageView
|
||||
android:id="@+id/checkmark"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginLeft="16dip"
|
||||
android:layout_marginRight="16dip"
|
||||
android:src="@drawable/btn_check_on_normal_holo_light" />
|
||||
<LinearLayout
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
android:layout_gravity="center_vertical">
|
||||
<TextView
|
||||
android:id="@+id/senders"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/long_string"
|
||||
android:textSize="@dimen/senders_font_size"
|
||||
android:lines="1" />
|
||||
<TextView
|
||||
android:id="@+id/subject"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/long_string"
|
||||
android:textSize="@dimen/subject_font_size"
|
||||
android:lines="2" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="80dip"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:gravity="right">
|
||||
<View
|
||||
android:id="@+id/color_chip"
|
||||
android:layout_width="@dimen/message_list_item_color_tip_width"
|
||||
android:layout_height="@dimen/message_list_item_color_tip_height"
|
||||
android:layout_marginRight="16dip" />
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal" >
|
||||
<ImageView
|
||||
android:id="@+id/paperclip"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_attachment_holo_light" />
|
||||
<TextView
|
||||
android:id="@+id/date"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dip"
|
||||
android:layout_marginRight="16dip"
|
||||
android:text="@string/long_string"
|
||||
android:lines="1" />
|
||||
</LinearLayout>
|
||||
<ImageView
|
||||
android:id="@+id/star"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="16dip"
|
||||
android:layout_marginRight="16dip"
|
||||
android:src="@drawable/btn_star_off_normal_email_holo_light" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
|
@ -0,0 +1,94 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2011 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
|
||||
<!-- This layout is used as a template to create custom view CanvasConversationHeaderView
|
||||
in normal mode. To be able to get the correct measurements, every source field should
|
||||
be populated with data here. E.g:
|
||||
- Text View should set text to a random long string (android:text="@string/long_string")
|
||||
- Image View should set source to a specific asset -->
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal">
|
||||
<ImageView
|
||||
android:id="@+id/checkmark"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginLeft="16dip"
|
||||
android:layout_marginRight="16dip"
|
||||
android:src="@drawable/btn_check_on_normal_holo_light" />
|
||||
<LinearLayout
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
android:layout_gravity="center_vertical">
|
||||
<TextView
|
||||
android:id="@+id/senders"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/long_string"
|
||||
android:textSize="@dimen/senders_font_size"
|
||||
android:lines="1" />
|
||||
<TextView
|
||||
android:id="@+id/subject"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/long_string"
|
||||
android:textSize="@dimen/subject_font_size"
|
||||
android:lines="2" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="136dip"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:gravity="right">
|
||||
<View
|
||||
android:id="@+id/color_chip"
|
||||
android:layout_width="@dimen/message_list_item_color_tip_width"
|
||||
android:layout_height="@dimen/message_list_item_color_tip_height"
|
||||
android:layout_marginRight="8dip"
|
||||
android:paddingTop="2dip" />
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal" >
|
||||
<ImageView
|
||||
android:id="@+id/paperclip"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_attachment_holo_light" />
|
||||
<TextView
|
||||
android:id="@+id/date"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="6dip"
|
||||
android:layout_marginRight="8dip"
|
||||
android:text="@string/long_string"
|
||||
android:lines="1" />
|
||||
</LinearLayout>
|
||||
<ImageView
|
||||
android:id="@+id/star"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="16dip"
|
||||
android:layout_marginRight="8dip"
|
||||
android:src="@drawable/btn_star_off_normal_email_holo_light" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
|
@ -0,0 +1,92 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2011 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
|
||||
<!-- This layout is used as a template to create custom message list item view
|
||||
in wide mode. To be able to get the correct measurements, every source field should
|
||||
be populated with data here. E.g:
|
||||
- Text View should set text to a random long string (android:text="@string/long_string")
|
||||
- Image View should set source to a specific asset -->
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal">
|
||||
<ImageView
|
||||
android:id="@+id/checkmark"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="16dip"
|
||||
android:layout_marginRight="16dip"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:src="@drawable/btn_check_on_normal_holo_light" />
|
||||
<TextView
|
||||
android:id="@+id/senders"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0.3"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:text="@string/long_string"
|
||||
android:textSize="@dimen/wide_senders_font_size"
|
||||
android:lines="1" />
|
||||
<TextView
|
||||
android:id="@+id/subject"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0.7"
|
||||
android:layout_marginLeft="16dip"
|
||||
android:layout_marginRight="16dip"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:text="@string/long_string"
|
||||
android:textSize="@dimen/subject_font_size"
|
||||
android:lines="2" />
|
||||
<RelativeLayout
|
||||
android:layout_width="144dip"
|
||||
android:layout_height="match_parent">
|
||||
<View
|
||||
android:id="@+id/color_chip"
|
||||
android:layout_width="@dimen/message_list_item_color_tip_width"
|
||||
android:layout_height="@dimen/message_list_item_color_tip_height"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:paddingTop="2dip" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/paperclip"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:src="@drawable/ic_attachment_holo_light" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/date"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:text="@string/long_string"
|
||||
android:lines="1" />
|
||||
|
||||
</RelativeLayout>
|
||||
<ImageView
|
||||
android:id="@+id/star"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="16dip"
|
||||
android:layout_marginRight="16dip"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:src="@drawable/btn_star_off_normal_email_holo_light" />
|
||||
</LinearLayout>
|
|
@ -190,4 +190,22 @@
|
|||
<item>@color/combined_view_account_color_8</item>
|
||||
<item>@color/combined_view_account_color_9</item>
|
||||
</array>
|
||||
|
||||
<!-- TODO: rename -->
|
||||
<!-- Values in dip of the message list item heights in the various modes:
|
||||
wide, normal, and narrow -->
|
||||
<integer-array name="conversation_heights">
|
||||
<item>61</item>
|
||||
<item>77</item>
|
||||
<item>77</item>
|
||||
</integer-array>
|
||||
|
||||
<!-- TODO: rename to subject_widths -->
|
||||
<!-- Length of the subject text in the message list items in dips for the
|
||||
various modes: wide, normal, and narrow -->
|
||||
<integer-array name="subject_lengths">
|
||||
<item>50</item>
|
||||
<item>50</item>
|
||||
<item>25</item>
|
||||
</integer-array>
|
||||
</resources>
|
||||
|
|
|
@ -19,26 +19,10 @@
|
|||
<resources>
|
||||
<dimen name="button_minWidth">100sp</dimen>
|
||||
<dimen name="message_list_item_text_size">16dip</dimen>
|
||||
<dimen name="message_list_item_checkbox_hit_width">64dip</dimen>
|
||||
<dimen name="message_list_item_favorite_hit_width">64dip</dimen>
|
||||
<dimen name="message_list_item_favorite_padding_right">16dip</dimen>
|
||||
<dimen name="message_list_item_badge_padding_top">8dip</dimen>
|
||||
<dimen name="message_list_item_badge_padding_right">-8dip</dimen>
|
||||
<dimen name="message_list_item_date_icon_width_wide">144dip</dimen>
|
||||
<dimen name="message_list_item_date_icon_width_narrow">112dip</dimen>
|
||||
<dimen name="message_list_item_sender_padding_top_narrow">10dip</dimen>
|
||||
<dimen name="message_list_item_sender_width">200dip</dimen>
|
||||
<dimen name="message_list_item_padding_large">32dip</dimen>
|
||||
<dimen name="message_list_item_padding_medium">6dip</dimen>
|
||||
<dimen name="message_list_item_padding_small">4dip</dimen>
|
||||
<dimen name="message_list_item_padding_very_small">2dip</dimen>
|
||||
<dimen name="message_list_item_height_wide">64dip</dimen>
|
||||
<dimen name="message_list_item_height_narrow">80dip</dimen>
|
||||
<dimen name="message_list_item_minimum_width_wide_mode">720dip</dimen>
|
||||
<dimen name="message_list_item_color_tip_width">35dip</dimen>
|
||||
<dimen name="message_list_item_color_tip_height">8dip</dimen>
|
||||
<dimen name="message_list_item_color_tip_right_margin_on_narrow">32dip</dimen>
|
||||
<dimen name="message_list_item_color_tip_right_margin_on_wide">65dip</dimen>
|
||||
|
||||
<dimen name="error_message_height">48dip</dimen>
|
||||
|
||||
|
@ -71,4 +55,11 @@
|
|||
|
||||
<dimen name="account_spinner_dropdown_account_name_max_width">352dip</dimen>
|
||||
|
||||
<!-- MessageListItem -->
|
||||
<dimen name="senders_font_size">14sp</dimen>
|
||||
<dimen name="wide_senders_font_size">16sp</dimen>
|
||||
<dimen name="subject_font_size">16sp</dimen>
|
||||
<dimen name="date_font_size">14sp</dimen>
|
||||
<dimen name="minimum_width_wide_mode">800dip</dimen>
|
||||
<dimen name="minimum_width_normal_mode">550dip</dimen>
|
||||
</resources>
|
||||
|
|
|
@ -1093,4 +1093,8 @@ save attachment.</string>
|
|||
<string name="mailbox_options_check_frequency_label">Mailbox check frequency</string>
|
||||
<!-- In Mailbox setings, label for email check lookback selector -->
|
||||
<string name="mailbox_options_lookback_label">Mailbox check lookback</string>
|
||||
|
||||
<!-- A long placeholder string to be used in template XML files message_list_item_*.xml.
|
||||
Used only in layout computation, and never actually exposed to the user. -->
|
||||
<string name="long_string" translatable="false">looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong</string>
|
||||
</resources>
|
||||
|
|
|
@ -25,8 +25,6 @@ import android.graphics.Bitmap;
|
|||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Paint.Align;
|
||||
import android.graphics.Paint.FontMetricsInt;
|
||||
import android.graphics.Typeface;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.Layout.Alignment;
|
||||
|
@ -38,7 +36,6 @@ import android.text.TextPaint;
|
|||
import android.text.TextUtils;
|
||||
import android.text.TextUtils.TruncateAt;
|
||||
import android.text.format.DateUtils;
|
||||
import android.text.style.BackgroundColorSpan;
|
||||
import android.text.style.StyleSpan;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
|
@ -56,6 +53,8 @@ public class MessageListItem extends View {
|
|||
/* package */ long mAccountId;
|
||||
|
||||
private MessagesAdapter mAdapter;
|
||||
private MessageListItemCoordinates mCoordinates;
|
||||
private Context mContext;
|
||||
|
||||
private boolean mDownEvent;
|
||||
|
||||
|
@ -77,13 +76,11 @@ public class MessageListItem extends View {
|
|||
init(context);
|
||||
}
|
||||
|
||||
// We always show two lines of subject/snippet
|
||||
private static final int MAX_SUBJECT_SNIPPET_LINES = 2;
|
||||
// Narrow mode shows sender/snippet and time/favorite stacked to save real estate; due to this,
|
||||
// it is also somewhat taller
|
||||
private static final int MODE_NARROW = 1;
|
||||
private static final int MODE_NARROW = MessageListItemCoordinates.NARROW_MODE;
|
||||
// Wide mode shows sender, snippet, time, and favorite spread out across the screen
|
||||
private static final int MODE_WIDE = 2;
|
||||
private static final int MODE_WIDE = MessageListItemCoordinates.WIDE_MODE;
|
||||
// Sentinel indicating that the view needs layout
|
||||
public static final int NEEDS_LAYOUT = -1;
|
||||
|
||||
|
@ -96,7 +93,6 @@ public class MessageListItem extends View {
|
|||
private static Bitmap sInviteIcon;
|
||||
private static Bitmap sFavoriteIconOff;
|
||||
private static Bitmap sFavoriteIconOn;
|
||||
private static int sFavoriteIconWidth;
|
||||
private static Bitmap sSelectedIconOn;
|
||||
private static Bitmap sSelectedIconOff;
|
||||
private static String sSubjectSnippetDivider;
|
||||
|
@ -105,6 +101,7 @@ public class MessageListItem extends View {
|
|||
public CharSequence mText;
|
||||
public CharSequence mSnippet;
|
||||
public String mSubject;
|
||||
private StaticLayout mSubjectLayout;
|
||||
public boolean mRead;
|
||||
public long mTimestamp;
|
||||
public boolean mHasAttachment = false;
|
||||
|
@ -117,31 +114,10 @@ public class MessageListItem extends View {
|
|||
|
||||
private int mViewWidth = 0;
|
||||
private int mViewHeight = 0;
|
||||
private int mSenderSnippetWidth;
|
||||
private int mSnippetWidth;
|
||||
private int mDateFaveWidth;
|
||||
|
||||
private static int sCheckboxHitWidth;
|
||||
private static int sDateIconWidthWide;
|
||||
private static int sDateIconWidthNarrow;
|
||||
private static int sFavoriteHitWidth;
|
||||
private static int sFavoritePaddingRight;
|
||||
private static int sBadgePaddingTop;
|
||||
private static int sBadgePaddingRight;
|
||||
private static int sSenderPaddingTopNarrow;
|
||||
private static int sSenderWidth;
|
||||
private static int sPaddingLarge;
|
||||
private static int sPaddingVerySmall;
|
||||
private static int sPaddingSmall;
|
||||
private static int sPaddingMedium;
|
||||
private static int sTextSize;
|
||||
private static int sItemHeightWide;
|
||||
private static int sItemHeightNarrow;
|
||||
private static int sMinimumWidthWideMode;
|
||||
private static int sColorTipWidth;
|
||||
private static int sColorTipHeight;
|
||||
private static int sColorTipRightMarginOnNarrow;
|
||||
private static int sColorTipRightMarginOnWide;
|
||||
|
||||
// Note: these cannot be shared Drawables because they are selectors which have state.
|
||||
private Drawable mReadSelector;
|
||||
|
@ -150,66 +126,28 @@ public class MessageListItem extends View {
|
|||
private Drawable mWideUnreadSelector;
|
||||
|
||||
public int mSnippetLineCount = NEEDS_LAYOUT;
|
||||
private final CharSequence[] mSnippetLines = new CharSequence[MAX_SUBJECT_SNIPPET_LINES];
|
||||
private CharSequence mFormattedSender;
|
||||
private CharSequence mFormattedDate;
|
||||
|
||||
private void init(Context context) {
|
||||
mContext = context;
|
||||
if (!sInit) {
|
||||
Resources r = context.getResources();
|
||||
sSubjectSnippetDivider = r.getString(R.string.message_list_subject_snippet_divider);
|
||||
sCheckboxHitWidth =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_checkbox_hit_width);
|
||||
sFavoriteHitWidth =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_favorite_hit_width);
|
||||
sFavoritePaddingRight =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_favorite_padding_right);
|
||||
sBadgePaddingTop =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_badge_padding_top);
|
||||
sBadgePaddingRight =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_badge_padding_right);
|
||||
sSenderPaddingTopNarrow =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_sender_padding_top_narrow);
|
||||
sDateIconWidthWide =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_date_icon_width_wide);
|
||||
sDateIconWidthNarrow =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_date_icon_width_narrow);
|
||||
sSenderWidth =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_sender_width);
|
||||
sPaddingLarge =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_padding_large);
|
||||
sPaddingMedium =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_padding_medium);
|
||||
sPaddingSmall =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_padding_small);
|
||||
sPaddingVerySmall =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_padding_very_small);
|
||||
sTextSize =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_text_size);
|
||||
sItemHeightWide =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_height_wide);
|
||||
sItemHeightNarrow =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_height_narrow);
|
||||
sMinimumWidthWideMode =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_minimum_width_wide_mode);
|
||||
sColorTipWidth =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_color_tip_width);
|
||||
sColorTipHeight =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_color_tip_height);
|
||||
sColorTipRightMarginOnNarrow =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_color_tip_right_margin_on_narrow);
|
||||
sColorTipRightMarginOnWide =
|
||||
r.getDimensionPixelSize(R.dimen.message_list_item_color_tip_right_margin_on_wide);
|
||||
|
||||
sDefaultPaint.setTypeface(Typeface.DEFAULT);
|
||||
sDefaultPaint.setTextSize(sTextSize);
|
||||
sDefaultPaint.setAntiAlias(true);
|
||||
sDatePaint.setTypeface(Typeface.DEFAULT);
|
||||
sDatePaint.setTextSize(sTextSize - 1);
|
||||
sDatePaint.setAntiAlias(true);
|
||||
sDatePaint.setTextAlign(Align.RIGHT);
|
||||
sBoldPaint.setTypeface(Typeface.DEFAULT_BOLD);
|
||||
sBoldPaint.setTextSize(sTextSize);
|
||||
sBoldPaint.setTypeface(Typeface.DEFAULT_BOLD);
|
||||
sBoldPaint.setAntiAlias(true);
|
||||
sHighlightPaint.setColor(TextUtilities.HIGHLIGHT_COLOR_INT);
|
||||
sAttachmentIcon = BitmapFactory.decodeResource(r, R.drawable.ic_badge_attachment);
|
||||
|
@ -223,7 +161,6 @@ public class MessageListItem extends View {
|
|||
sSelectedIconOn =
|
||||
BitmapFactory.decodeResource(r, R.drawable.btn_check_on_normal_holo_light);
|
||||
|
||||
sFavoriteIconWidth = sFavoriteIconOff.getWidth();
|
||||
sInit = true;
|
||||
}
|
||||
}
|
||||
|
@ -235,16 +172,12 @@ public class MessageListItem extends View {
|
|||
* @return The mode of the view
|
||||
*/
|
||||
private int getViewMode(int width) {
|
||||
int mode = MODE_NARROW;
|
||||
if (width > sMinimumWidthWideMode) {
|
||||
mode = MODE_WIDE;
|
||||
}
|
||||
return mode;
|
||||
return MessageListItemCoordinates.getMode(mContext, width);
|
||||
}
|
||||
|
||||
private Drawable mCurentBackground = null; // Only used by updateBackground()
|
||||
|
||||
/* package */ void updateBackground() {
|
||||
private void updateBackground() {
|
||||
final Drawable newBackground;
|
||||
if (mRead) {
|
||||
if (mMode == MODE_WIDE) {
|
||||
|
@ -300,43 +233,19 @@ public class MessageListItem extends View {
|
|||
}
|
||||
mText = ssb;
|
||||
|
||||
if (mMode == MODE_WIDE) {
|
||||
mDateFaveWidth = sFavoriteHitWidth + sDateIconWidthWide;
|
||||
} else {
|
||||
mDateFaveWidth = sDateIconWidthNarrow;
|
||||
}
|
||||
mSenderSnippetWidth = mViewWidth - mDateFaveWidth - sCheckboxHitWidth;
|
||||
|
||||
// In wide mode, we use 3/4 for snippet and 1/4 for sender
|
||||
mSnippetWidth = mSenderSnippetWidth;
|
||||
if (mMode == MODE_WIDE) {
|
||||
mSnippetWidth = mSenderSnippetWidth - sSenderWidth - sPaddingLarge;
|
||||
}
|
||||
|
||||
// Create a StaticLayout with our snippet to get the line breaks
|
||||
StaticLayout layout = new StaticLayout(mText, 0, mText.length(), sDefaultPaint,
|
||||
mSnippetWidth, Alignment.ALIGN_NORMAL, 1, 0, true);
|
||||
// Get the number of lines needed to render the whole snippet
|
||||
mSnippetLineCount = layout.getLineCount();
|
||||
// Go through our maximum number of lines, and save away what we'll end up displaying
|
||||
// for those lines
|
||||
for (int i = 0; i < MAX_SUBJECT_SNIPPET_LINES; i++) {
|
||||
int start = layout.getLineStart(i);
|
||||
if (i == MAX_SUBJECT_SNIPPET_LINES - 1) {
|
||||
int end = mText.length();
|
||||
if (start > end) continue;
|
||||
// For the final line, ellipsize the text to our width
|
||||
mSnippetLines[i] = TextUtils.ellipsize(mText.subSequence(start, end), sDefaultPaint,
|
||||
mSnippetWidth, TruncateAt.END);
|
||||
} else {
|
||||
// Just extract from start to end
|
||||
mSnippetLines[i] = mText.subSequence(start, layout.getLineEnd(i));
|
||||
}
|
||||
sDefaultPaint.setTextSize(mCoordinates.subjectFontSize);
|
||||
mSubjectLayout = new StaticLayout(mText, sDefaultPaint,
|
||||
mCoordinates.subjectWidth, Alignment.ALIGN_NORMAL, 1, 0, true);
|
||||
if (mCoordinates.subjectLineCount < mSubjectLayout.getLineCount()) {
|
||||
// TODO: ellipsize.
|
||||
int end = mSubjectLayout.getLineEnd(mCoordinates.subjectLineCount - 1);
|
||||
mSubjectLayout = new StaticLayout(mText.subSequence(0, end),
|
||||
sDefaultPaint, mCoordinates.subjectWidth, Alignment.ALIGN_NORMAL, 1, 0, true);
|
||||
}
|
||||
|
||||
// Now, format the sender for its width
|
||||
TextPaint senderPaint = mRead ? sDefaultPaint : sBoldPaint;
|
||||
int senderWidth = (mMode == MODE_WIDE) ? sSenderWidth : mSenderSnippetWidth;
|
||||
int senderWidth = mCoordinates.sendersWidth;
|
||||
// And get the ellipsized string for the calculated width
|
||||
if (TextUtils.isEmpty(mSender)) {
|
||||
mFormattedSender = "";
|
||||
|
@ -345,9 +254,7 @@ public class MessageListItem extends View {
|
|||
TruncateAt.END);
|
||||
}
|
||||
// Get a nicely formatted date string (relative to today)
|
||||
String date = DateUtils.getRelativeTimeSpanString(getContext(), mTimestamp).toString();
|
||||
// And make it fit to our size
|
||||
mFormattedDate = TextUtils.ellipsize(date, sDatePaint, sDateIconWidthWide, TruncateAt.END);
|
||||
mFormattedDate = DateUtils.getRelativeTimeSpanString(getContext(), mTimestamp).toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -404,133 +311,72 @@ public class MessageListItem extends View {
|
|||
super.draw(canvas);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
|
||||
mCoordinates = MessageListItemCoordinates.forWidth(mContext, mViewWidth);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
if (mSnippetLineCount == NEEDS_LAYOUT) {
|
||||
calculateDrawingData();
|
||||
}
|
||||
// Snippet starts at right of checkbox
|
||||
int snippetX = sCheckboxHitWidth;
|
||||
int snippetY;
|
||||
int lineHeight = (int)sDefaultPaint.getFontSpacing() + sPaddingVerySmall;
|
||||
FontMetricsInt fontMetrics = sDefaultPaint.getFontMetricsInt();
|
||||
int ascent = fontMetrics.ascent;
|
||||
int descent = fontMetrics.descent;
|
||||
int senderY;
|
||||
|
||||
if (mMode == MODE_WIDE) {
|
||||
// Get the right starting point for the snippet
|
||||
snippetX += sSenderWidth + sPaddingLarge;
|
||||
// And center the sender and snippet
|
||||
senderY = (mViewHeight - descent - ascent) / 2;
|
||||
snippetY = ((mViewHeight - (2 * lineHeight)) / 2) - ascent;
|
||||
} else {
|
||||
senderY = -ascent + sSenderPaddingTopNarrow;
|
||||
snippetY = senderY + lineHeight + sPaddingVerySmall;
|
||||
}
|
||||
|
||||
// Draw the color chip
|
||||
// Draw the color chip indicating the mailbox this belongs to
|
||||
if (mColorChipPaint != null) {
|
||||
final int rightMargin = (mMode == MODE_WIDE)
|
||||
? sColorTipRightMarginOnWide : sColorTipRightMarginOnNarrow;
|
||||
final int x = mViewWidth - rightMargin - sColorTipWidth;
|
||||
canvas.drawRect(x, 0, x + sColorTipWidth, sColorTipHeight, mColorChipPaint);
|
||||
canvas.drawRect(
|
||||
mCoordinates.chipX, mCoordinates.chipY,
|
||||
mCoordinates.chipX + mCoordinates.chipWidth,
|
||||
mCoordinates.chipY + mCoordinates.chipHeight,
|
||||
mColorChipPaint);
|
||||
}
|
||||
|
||||
// Draw the checkbox
|
||||
int checkboxLeft = (sCheckboxHitWidth - sSelectedIconOff.getWidth()) / 2;
|
||||
int checkboxTop = (mViewHeight - sSelectedIconOff.getHeight()) / 2;
|
||||
canvas.drawBitmap(mAdapter.isSelected(this) ? sSelectedIconOn : sSelectedIconOff,
|
||||
checkboxLeft, checkboxTop, sDefaultPaint);
|
||||
mCoordinates.checkmarkX, mCoordinates.checkmarkY, sDefaultPaint);
|
||||
|
||||
// Draw the sender name
|
||||
canvas.drawText(mFormattedSender, 0, mFormattedSender.length(), sCheckboxHitWidth, senderY,
|
||||
canvas.drawText(mFormattedSender, 0, mFormattedSender.length(),
|
||||
mCoordinates.sendersX, mCoordinates.sendersY - mCoordinates.sendersAscent,
|
||||
mRead ? sDefaultPaint : sBoldPaint);
|
||||
|
||||
// Draw each of the snippet lines
|
||||
for (int i = 0; i < MAX_SUBJECT_SNIPPET_LINES && i < mSnippetLineCount; i++) {
|
||||
CharSequence line = mSnippetLines[i];
|
||||
int drawX = snippetX;
|
||||
if (line != null) {
|
||||
SpannableStringBuilder ssb = (SpannableStringBuilder)line;
|
||||
Object[] spans = ssb.getSpans(0, line.length(), Object.class);
|
||||
int curr = 0;
|
||||
for (Object span: spans) {
|
||||
if (span != null) {
|
||||
int spanStart = ssb.getSpanStart(span);
|
||||
int spanEnd = ssb.getSpanEnd(span);
|
||||
if (curr < spanStart) {
|
||||
canvas.drawText(line, curr, spanStart, drawX, snippetY, sDefaultPaint);
|
||||
drawX += sDefaultPaint.measureText(line, curr, spanStart);
|
||||
}
|
||||
TextPaint spanPaint =
|
||||
(span instanceof StyleSpan) ? sBoldPaint : sDefaultPaint;
|
||||
float textWidth = spanPaint.measureText(line, spanStart, spanEnd);
|
||||
if (span instanceof BackgroundColorSpan) {
|
||||
canvas.drawRect(drawX, snippetY + ascent, drawX + textWidth,
|
||||
snippetY + descent, sHighlightPaint);
|
||||
}
|
||||
canvas.drawText(line, spanStart, spanEnd, drawX, snippetY, spanPaint);
|
||||
drawX += textWidth;
|
||||
curr = spanEnd;
|
||||
}
|
||||
}
|
||||
canvas.drawText(line, curr, line.length(), drawX, snippetY, sDefaultPaint);
|
||||
snippetY += lineHeight;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the attachment and invite icons, if necessary
|
||||
int datePaddingRight;
|
||||
if (mMode == MODE_WIDE) {
|
||||
datePaddingRight = sFavoriteHitWidth;
|
||||
} else {
|
||||
datePaddingRight = sPaddingLarge;
|
||||
}
|
||||
int left = mViewWidth - datePaddingRight - (int)sDefaultPaint.measureText(mFormattedDate,
|
||||
0, mFormattedDate.length()) - sPaddingMedium;
|
||||
|
||||
int iconTop;
|
||||
if (mHasAttachment) {
|
||||
left -= sAttachmentIcon.getWidth();
|
||||
if (mMode == MODE_WIDE) {
|
||||
iconTop = (mViewHeight - sAttachmentIcon.getHeight()) / 2;
|
||||
left -= sPaddingSmall;
|
||||
} else {
|
||||
iconTop = senderY - sAttachmentIcon.getHeight() + sBadgePaddingTop;
|
||||
left -= sBadgePaddingRight;
|
||||
}
|
||||
canvas.drawBitmap(sAttachmentIcon, left, iconTop, sDefaultPaint);
|
||||
}
|
||||
if (mHasInvite) {
|
||||
left -= sInviteIcon.getWidth();
|
||||
if (mMode == MODE_WIDE) {
|
||||
iconTop = (mViewHeight - sInviteIcon.getHeight()) / 2;
|
||||
left -= sPaddingSmall;
|
||||
} else {
|
||||
iconTop = senderY - sInviteIcon.getHeight() + sBadgePaddingTop;
|
||||
left -= sBadgePaddingRight;
|
||||
}
|
||||
canvas.drawBitmap(sInviteIcon, left, iconTop, sDefaultPaint);
|
||||
}
|
||||
// Subject and snippet.
|
||||
sDefaultPaint.setTextSize(mCoordinates.subjectFontSize);
|
||||
sDefaultPaint.setTypeface(Typeface.DEFAULT);
|
||||
canvas.save();
|
||||
canvas.translate(
|
||||
mCoordinates.subjectX,
|
||||
mCoordinates.subjectY);
|
||||
mSubjectLayout.draw(canvas);
|
||||
canvas.restore();
|
||||
|
||||
// Draw the date
|
||||
canvas.drawText(mFormattedDate, 0, mFormattedDate.length(), mViewWidth - datePaddingRight,
|
||||
senderY, sDatePaint);
|
||||
sDatePaint.setTextSize(mCoordinates.dateFontSize);
|
||||
int dateX = mCoordinates.dateXEnd
|
||||
- (int) sDatePaint.measureText(mFormattedDate, 0, mFormattedDate.length());
|
||||
|
||||
canvas.drawText(mFormattedDate, 0, mFormattedDate.length(),
|
||||
dateX, mCoordinates.dateY - mCoordinates.dateAscent, sDatePaint);
|
||||
|
||||
// Draw the favorite icon
|
||||
int faveLeft = mViewWidth - sFavoriteIconWidth;
|
||||
if (mMode == MODE_WIDE) {
|
||||
faveLeft -= sFavoritePaddingRight;
|
||||
} else {
|
||||
faveLeft -= sPaddingLarge;
|
||||
canvas.drawBitmap(mIsFavorite ? sFavoriteIconOn : sFavoriteIconOff,
|
||||
mCoordinates.starX, mCoordinates.starY, sDefaultPaint);
|
||||
|
||||
// TODO: deal with the icon layouts better from the coordinate class so that this logic
|
||||
// doesn't have to exist.
|
||||
// Draw the attachment and invite icons, if necessary.
|
||||
int iconsLeft = dateX;
|
||||
if (mHasAttachment) {
|
||||
iconsLeft = iconsLeft - sAttachmentIcon.getWidth();
|
||||
canvas.drawBitmap(sAttachmentIcon, iconsLeft, mCoordinates.paperclipY, sDefaultPaint);
|
||||
}
|
||||
int faveTop = (mViewHeight - sFavoriteIconOff.getHeight()) / 2;
|
||||
if (mMode == MODE_NARROW) {
|
||||
faveTop += sSenderPaddingTopNarrow;
|
||||
if (mHasInvite) {
|
||||
iconsLeft -= sInviteIcon.getWidth();
|
||||
canvas.drawBitmap(sInviteIcon, iconsLeft, mCoordinates.paperclipY, sDefaultPaint);
|
||||
}
|
||||
canvas.drawBitmap(mIsFavorite ? sFavoriteIconOn : sFavoriteIconOff, faveLeft, faveTop,
|
||||
sDefaultPaint);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -550,8 +396,8 @@ public class MessageListItem extends View {
|
|||
public boolean onTouchEvent(MotionEvent event) {
|
||||
boolean handled = false;
|
||||
int touchX = (int) event.getX();
|
||||
int checkRight = sCheckboxHitWidth;
|
||||
int starLeft = mViewWidth - sFavoriteHitWidth;
|
||||
int checkRight = mCoordinates.checkmarkWidthIncludingMargins;
|
||||
int starLeft = mViewWidth - mCoordinates.starWidthIncludingMargins;
|
||||
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
|
|
|
@ -0,0 +1,311 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package com.android.email.activity;
|
||||
|
||||
import com.android.email.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Typeface;
|
||||
import android.text.TextPaint;
|
||||
import android.util.SparseArray;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.MeasureSpec;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewParent;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* Represents the coordinates of elements inside a CanvasConversationHeaderView
|
||||
* (eg, checkmark, star, subject, sender, labels, etc.) It will inflate a view,
|
||||
* and record the coordinates of each element after layout. This will allows us
|
||||
* to easily improve performance by creating custom view while still defining
|
||||
* layout in XML files.
|
||||
*/
|
||||
public class MessageListItemCoordinates {
|
||||
// Modes.
|
||||
public static final int WIDE_MODE = 0;
|
||||
public static final int NORMAL_MODE = 1;
|
||||
public static final int NARROW_MODE = 2;
|
||||
|
||||
// Static threshold.
|
||||
private static int MINIMUM_WIDTH_WIDE_MODE = -1;
|
||||
private static int MINIMUM_WIDTH_NORMAL_MODE = -1;
|
||||
private static int[] CONVERSATION_HEIGHTS;
|
||||
private static int[] SUBJECT_LENGTHS;
|
||||
|
||||
// Checkmark.
|
||||
int checkmarkX;
|
||||
int checkmarkY;
|
||||
int checkmarkWidthIncludingMargins;
|
||||
int checkmarkHeightIncludingMargins;
|
||||
|
||||
// Star.
|
||||
int starX;
|
||||
int starY;
|
||||
int starWidthIncludingMargins;
|
||||
int starHeightIncludingMargins;
|
||||
|
||||
// Senders.
|
||||
int sendersX;
|
||||
int sendersY;
|
||||
int sendersWidth;
|
||||
int sendersLineCount;
|
||||
int sendersLineHeight;
|
||||
int sendersFontSize;
|
||||
int sendersAscent;
|
||||
|
||||
// Subject.
|
||||
int subjectX;
|
||||
int subjectY;
|
||||
int subjectWidth;
|
||||
int subjectLineCount;
|
||||
int subjectLineHeight;
|
||||
int subjectFontSize;
|
||||
int subjectAscent;
|
||||
|
||||
// Color chip.
|
||||
int chipX;
|
||||
int chipY;
|
||||
int chipWidth;
|
||||
int chipHeight;
|
||||
|
||||
// Date.
|
||||
int dateXEnd;
|
||||
int dateY;
|
||||
int dateFontSize;
|
||||
int dateAscent;
|
||||
|
||||
// Paperclip.
|
||||
int paperclipY;
|
||||
|
||||
// Cache to save Coordinates based on view width.
|
||||
private static SparseArray<MessageListItemCoordinates> mCache =
|
||||
new SparseArray<MessageListItemCoordinates>();
|
||||
|
||||
private static TextPaint sPaint = new TextPaint();
|
||||
|
||||
static {
|
||||
sPaint.setTypeface(Typeface.DEFAULT);
|
||||
sPaint.setAntiAlias(true);
|
||||
}
|
||||
|
||||
// Not directly instantiable.
|
||||
private MessageListItemCoordinates() {}
|
||||
|
||||
/**
|
||||
* Returns the mode of the header view (Wide/Normal/Narrow) given the its
|
||||
* measured width.
|
||||
*/
|
||||
public static int getMode(Context context, int width) {
|
||||
Resources res = context.getResources();
|
||||
if (MINIMUM_WIDTH_NORMAL_MODE <= 0) {
|
||||
MINIMUM_WIDTH_WIDE_MODE = res.getDimensionPixelSize(R.dimen.minimum_width_wide_mode);
|
||||
MINIMUM_WIDTH_NORMAL_MODE = res
|
||||
.getDimensionPixelSize(R.dimen.minimum_width_normal_mode);
|
||||
}
|
||||
|
||||
// Choose the correct mode based on view width.
|
||||
int mode = NARROW_MODE;
|
||||
if (width > MINIMUM_WIDTH_NORMAL_MODE) {
|
||||
mode = NORMAL_MODE;
|
||||
}
|
||||
if (width > MINIMUM_WIDTH_WIDE_MODE) {
|
||||
mode = WIDE_MODE;
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the layout id to be inflated in this mode.
|
||||
*/
|
||||
private static int getLayoutId(int mode) {
|
||||
switch (mode) {
|
||||
case WIDE_MODE:
|
||||
return R.layout.message_list_item_wide;
|
||||
case NORMAL_MODE:
|
||||
return R.layout.message_list_item_normal;
|
||||
case NARROW_MODE:
|
||||
return R.layout.message_list_item_narrow;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown conversation header view mode " + mode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value array multiplied by the specified density.
|
||||
*/
|
||||
public static int[] getDensityDependentArray(int[] values, float density) {
|
||||
int result[] = new int[values.length];
|
||||
for (int i = 0; i < values.length; ++i) {
|
||||
result[i] = (int) (values[i] * density);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the height of the view in this mode.
|
||||
*/
|
||||
public static int getHeight(Context context, int mode) {
|
||||
Resources res = context.getResources();
|
||||
float density = res.getDisplayMetrics().scaledDensity;
|
||||
if (CONVERSATION_HEIGHTS == null) {
|
||||
CONVERSATION_HEIGHTS = getDensityDependentArray(
|
||||
res.getIntArray(R.array.conversation_heights), density);
|
||||
}
|
||||
return CONVERSATION_HEIGHTS[mode];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the x coordinates of a view by tracing up its hierarchy.
|
||||
*/
|
||||
private static int getX(View view) {
|
||||
int x = 0;
|
||||
while (view != null) {
|
||||
x += (int) view.getX();
|
||||
ViewParent parent = view.getParent();
|
||||
view = parent != null ? (View) parent : null;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the y coordinates of a view by tracing up its hierarchy.
|
||||
*/
|
||||
private static int getY(View view) {
|
||||
int y = 0;
|
||||
while (view != null) {
|
||||
y += (int) view.getY();
|
||||
ViewParent parent = view.getParent();
|
||||
view = parent != null ? (View) parent : null;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the width of a view.
|
||||
*
|
||||
* @param includeMargins whether or not to include margins when calculating
|
||||
* width.
|
||||
*/
|
||||
public static int getWidth(View view, boolean includeMargins) {
|
||||
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
|
||||
return view.getWidth() + (includeMargins ? params.leftMargin + params.rightMargin : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the height of a view.
|
||||
*
|
||||
* @param includeMargins whether or not to include margins when calculating
|
||||
* height.
|
||||
*/
|
||||
public static int getHeight(View view, boolean includeMargins) {
|
||||
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
|
||||
return view.getHeight() + (includeMargins ? params.topMargin + params.bottomMargin : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of lines of this text view.
|
||||
*/
|
||||
private static int getLineCount(TextView textView) {
|
||||
return textView.getHeight() / textView.getLineHeight();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length (maximum of characters) of subject in this mode.
|
||||
*/
|
||||
public static int getSubjectLength(Context context, int mode) {
|
||||
Resources res = context.getResources();
|
||||
if (SUBJECT_LENGTHS == null) {
|
||||
SUBJECT_LENGTHS = res.getIntArray(R.array.subject_lengths);
|
||||
}
|
||||
return SUBJECT_LENGTHS[mode];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns coordinates for elements inside a conversation header view given
|
||||
* the view width.
|
||||
*/
|
||||
public static MessageListItemCoordinates forWidth(Context context, int width) {
|
||||
MessageListItemCoordinates coordinates = mCache.get(width);
|
||||
if (coordinates == null) {
|
||||
coordinates = new MessageListItemCoordinates();
|
||||
mCache.put(width, coordinates);
|
||||
// TODO: make the field computation done inside of the constructor and mark fields final
|
||||
|
||||
// Layout the appropriate view.
|
||||
int mode = getMode(context, width);
|
||||
int height = getHeight(context, mode);
|
||||
View view = LayoutInflater.from(context).inflate(getLayoutId(mode), null);
|
||||
int widthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
|
||||
int heightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
|
||||
view.measure(widthSpec, heightSpec);
|
||||
view.layout(0, 0, width, height);
|
||||
|
||||
// Records coordinates.
|
||||
View checkmark = view.findViewById(R.id.checkmark);
|
||||
coordinates.checkmarkX = getX(checkmark);
|
||||
coordinates.checkmarkY = getY(checkmark);
|
||||
coordinates.checkmarkWidthIncludingMargins = getWidth(checkmark, true);
|
||||
|
||||
View star = view.findViewById(R.id.star);
|
||||
coordinates.starX = getX(star);
|
||||
coordinates.starY = getY(star);
|
||||
coordinates.starWidthIncludingMargins = getWidth(star, true);
|
||||
|
||||
TextView senders = (TextView) view.findViewById(R.id.senders);
|
||||
coordinates.sendersX = getX(senders);
|
||||
coordinates.sendersY = getY(senders);
|
||||
coordinates.sendersWidth = getWidth(senders, false);
|
||||
coordinates.sendersLineCount = getLineCount(senders);
|
||||
coordinates.sendersLineHeight = senders.getLineHeight();
|
||||
coordinates.sendersFontSize = (int) senders.getTextSize();
|
||||
sPaint.setTextSize(coordinates.sendersFontSize);
|
||||
coordinates.sendersAscent = (int) sPaint.ascent();
|
||||
|
||||
TextView subject = (TextView) view.findViewById(R.id.subject);
|
||||
coordinates.subjectX = getX(subject);
|
||||
coordinates.subjectY = getY(subject);
|
||||
coordinates.subjectWidth = getWidth(subject, false);
|
||||
coordinates.subjectLineCount = getLineCount(subject);
|
||||
coordinates.subjectLineHeight = subject.getLineHeight();
|
||||
coordinates.subjectFontSize = (int) subject.getTextSize();
|
||||
sPaint.setTextSize(coordinates.subjectFontSize);
|
||||
coordinates.subjectAscent = (int) sPaint.ascent();
|
||||
|
||||
View chip = view.findViewById(R.id.color_chip);
|
||||
coordinates.chipX = getX(chip);
|
||||
coordinates.chipY = getY(chip);
|
||||
coordinates.chipWidth = getWidth(chip, false);
|
||||
coordinates.chipHeight = getHeight(chip, false);
|
||||
|
||||
TextView date = (TextView) view.findViewById(R.id.date);
|
||||
coordinates.dateXEnd = getX(date) + date.getWidth();
|
||||
coordinates.dateY = getY(date);
|
||||
coordinates.dateFontSize = (int) date.getTextSize();
|
||||
sPaint.setTextSize(coordinates.dateFontSize);
|
||||
coordinates.dateAscent = (int) sPaint.ascent();
|
||||
|
||||
// The x-value is computed relative to the date.
|
||||
View paperclip = view.findViewById(R.id.paperclip);
|
||||
coordinates.paperclipY = getY(paperclip);
|
||||
}
|
||||
return coordinates;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue