1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14 package android.support.v17.leanback.widget; 15 16 import android.graphics.Paint; 17 import android.graphics.Paint.FontMetricsInt; 18 import android.support.v17.leanback.R; 19 import android.text.TextUtils; 20 import android.view.LayoutInflater; 21 import android.view.View; 22 import android.view.ViewGroup; 23 import android.widget.TextView; 24 25 /** 26 * An abstract {@link Presenter} for rendering a detailed description of an 27 * item. Typically this Presenter will be used in a DetailsOveriewRowPresenter. 28 * 29 * <p>Subclasses will override {@link #onBindDescription} to implement the data 30 * binding for this Presenter. 31 */ 32 public abstract class AbstractDetailsDescriptionPresenter extends Presenter { 33 34 public static class ViewHolder extends Presenter.ViewHolder { 35 private final TextView mTitle; 36 private final TextView mSubtitle; 37 private final TextView mBody; 38 private final int mTitleMargin; 39 private final int mUnderTitleBaselineMargin; 40 private final int mUnderSubtitleBaselineMargin; 41 private final int mTitleLineSpacing; 42 private final int mBodyLineSpacing; 43 private final int mBodyMaxLines; 44 private final int mBodyMinLines; 45 private final FontMetricsInt mTitleFontMetricsInt; 46 private final FontMetricsInt mSubtitleFontMetricsInt; 47 private final FontMetricsInt mBodyFontMetricsInt; 48 ViewHolder(View view)49 public ViewHolder(View view) { 50 super(view); 51 mTitle = (TextView) view.findViewById(R.id.lb_details_description_title); 52 mSubtitle = (TextView) view.findViewById(R.id.lb_details_description_subtitle); 53 mBody = (TextView) view.findViewById(R.id.lb_details_description_body); 54 55 FontMetricsInt titleFontMetricsInt = getFontMetricsInt(mTitle); 56 final int titleAscent = view.getResources().getDimensionPixelSize( 57 R.dimen.lb_details_description_title_baseline); 58 // Ascent is negative 59 mTitleMargin = titleAscent + titleFontMetricsInt.ascent; 60 61 mUnderTitleBaselineMargin = view.getResources().getDimensionPixelSize( 62 R.dimen.lb_details_description_under_title_baseline_margin); 63 mUnderSubtitleBaselineMargin = view.getResources().getDimensionPixelSize( 64 R.dimen.lb_details_description_under_subtitle_baseline_margin); 65 66 mTitleLineSpacing = view.getResources().getDimensionPixelSize( 67 R.dimen.lb_details_description_title_line_spacing); 68 mBodyLineSpacing = view.getResources().getDimensionPixelSize( 69 R.dimen.lb_details_description_body_line_spacing); 70 71 mBodyMaxLines = view.getResources().getInteger( 72 R.integer.lb_details_description_body_max_lines); 73 mBodyMinLines = view.getResources().getInteger( 74 R.integer.lb_details_description_body_min_lines); 75 76 mTitleFontMetricsInt = getFontMetricsInt(mTitle); 77 mSubtitleFontMetricsInt = getFontMetricsInt(mSubtitle); 78 mBodyFontMetricsInt = getFontMetricsInt(mBody); 79 80 mTitle.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { 81 @Override 82 public void onLayoutChange(View v, int left, int top, int right, 83 int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { 84 mBody.setMaxLines(mTitle.getLineCount() > 1 ? mBodyMinLines : mBodyMaxLines); 85 } 86 }); 87 } 88 getTitle()89 public TextView getTitle() { 90 return mTitle; 91 } 92 getSubtitle()93 public TextView getSubtitle() { 94 return mSubtitle; 95 } 96 getBody()97 public TextView getBody() { 98 return mBody; 99 } 100 getFontMetricsInt(TextView textView)101 private FontMetricsInt getFontMetricsInt(TextView textView) { 102 Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); 103 paint.setTextSize(textView.getTextSize()); 104 paint.setTypeface(textView.getTypeface()); 105 return paint.getFontMetricsInt(); 106 } 107 } 108 109 @Override onCreateViewHolder(ViewGroup parent)110 public final ViewHolder onCreateViewHolder(ViewGroup parent) { 111 View v = LayoutInflater.from(parent.getContext()) 112 .inflate(R.layout.lb_details_description, parent, false); 113 return new ViewHolder(v); 114 } 115 116 @Override onBindViewHolder(Presenter.ViewHolder viewHolder, Object item)117 public final void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) { 118 ViewHolder vh = (ViewHolder) viewHolder; 119 onBindDescription(vh, item); 120 121 boolean hasTitle = true; 122 if (TextUtils.isEmpty(vh.mTitle.getText())) { 123 vh.mTitle.setVisibility(View.GONE); 124 hasTitle = false; 125 } else { 126 vh.mTitle.setVisibility(View.VISIBLE); 127 vh.mTitle.setLineSpacing(vh.mTitleLineSpacing - vh.mTitle.getLineHeight() + 128 vh.mTitle.getLineSpacingExtra(), vh.mTitle.getLineSpacingMultiplier()); 129 } 130 setTopMargin(vh.mTitle, vh.mTitleMargin); 131 132 boolean hasSubtitle = true; 133 if (TextUtils.isEmpty(vh.mSubtitle.getText())) { 134 vh.mSubtitle.setVisibility(View.GONE); 135 hasSubtitle = false; 136 } else { 137 vh.mSubtitle.setVisibility(View.VISIBLE); 138 if (hasTitle) { 139 setTopMargin(vh.mSubtitle, vh.mUnderTitleBaselineMargin + 140 vh.mSubtitleFontMetricsInt.ascent - vh.mTitleFontMetricsInt.descent); 141 } else { 142 setTopMargin(vh.mSubtitle, 0); 143 } 144 } 145 146 if (TextUtils.isEmpty(vh.mBody.getText())) { 147 vh.mBody.setVisibility(View.GONE); 148 } else { 149 vh.mBody.setVisibility(View.VISIBLE); 150 vh.mBody.setLineSpacing(vh.mBodyLineSpacing - vh.mBody.getLineHeight() + 151 vh.mBody.getLineSpacingExtra(), vh.mBody.getLineSpacingMultiplier()); 152 153 if (hasSubtitle) { 154 setTopMargin(vh.mBody, vh.mUnderSubtitleBaselineMargin + 155 vh.mBodyFontMetricsInt.ascent - vh.mSubtitleFontMetricsInt.descent); 156 } else if (hasTitle) { 157 setTopMargin(vh.mBody, vh.mUnderTitleBaselineMargin + 158 vh.mBodyFontMetricsInt.ascent - vh.mTitleFontMetricsInt.descent); 159 } else { 160 setTopMargin(vh.mBody, 0); 161 } 162 } 163 } 164 165 /** 166 * Binds the data from the item referenced in the DetailsOverviewRow to the 167 * ViewHolder. 168 * 169 * @param vh The ViewHolder for this details description view. 170 * @param item The item from the DetailsOverviewRow being presented. 171 */ onBindDescription(ViewHolder vh, Object item)172 protected abstract void onBindDescription(ViewHolder vh, Object item); 173 174 @Override onUnbindViewHolder(Presenter.ViewHolder viewHolder)175 public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) {} 176 setTopMargin(TextView textView, int topMargin)177 private void setTopMargin(TextView textView, int topMargin) { 178 ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) textView.getLayoutParams(); 179 lp.topMargin = topMargin; 180 textView.setLayoutParams(lp); 181 } 182 } 183