-
-
Save weidiaoxiang/6547230 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright 2013 Google Inc. | |
* | |
* 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.example.android.charsperline; | |
import android.app.Activity; | |
import android.os.Bundle; | |
import android.util.Log; | |
import android.view.View; | |
import android.view.ViewTreeObserver; | |
import android.widget.TextView; | |
public class CharsPerLineActivity extends Activity { | |
private static final String TAG = "CharsPerLineActivity"; | |
private TextView mStatusView; | |
private View mContainerView; | |
private TextView mTextView; | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_main); | |
mStatusView = (TextView) findViewById(R.id.status); | |
mContainerView = findViewById(R.id.container); | |
mTextView = (TextView) findViewById(R.id.text); | |
mTextView.getViewTreeObserver().addOnGlobalLayoutListener( | |
new ViewTreeObserver.OnGlobalLayoutListener() { | |
@Override | |
public void onGlobalLayout() { | |
Log.d(TAG, "Parent: " + mContainerView.getWidth() | |
+ ", Child: " + mTextView.getWidth()); | |
int maxCharsPerLine = CharsPerLineUtil.getMaxCharsPerLine(mTextView); | |
boolean badCpl = maxCharsPerLine < CharsPerLineUtil.RECOMMENDED_MIN_CPL | |
|| maxCharsPerLine > CharsPerLineUtil.RECOMMENDED_MAX_CPL; | |
mStatusView.setTextColor(badCpl ? 0xffff4444 : 0x88ffffff); | |
mStatusView.setText("Maximum measure: " + maxCharsPerLine + " CPL"); | |
} | |
}); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright 2013 Google Inc. | |
* | |
* 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.example.android.charsperline; | |
import android.text.Layout; | |
import android.util.Log; | |
import android.widget.TextView; | |
/** | |
* Helper utilities useful during debugging that compute the maximum number of characters per line | |
* in a {@link TextView} or {@link Layout}. | |
*/ | |
public class CharsPerLineUtil { | |
private static final String TAG = "CharsPerLineUtil"; | |
public static final int RECOMMENDED_MIN_CPL = 45; | |
public static final int RECOMMENDED_MAX_CPL = 75; | |
/** | |
* Compute the maximum number of characters per line in the given {@link TextView}. | |
*/ | |
public static int getMaxCharsPerLine(TextView textView) { | |
return getMaxCharsPerLine(textView.getLayout()); | |
} | |
/** | |
* Compute the maximum number of characters per line in the given {@link Layout}. | |
*/ | |
public static int getMaxCharsPerLine(Layout layout) { | |
int maxChars = 0; | |
int maxIndex = -1; | |
for (int i = layout.getLineCount() - 1; i >= 0; i--) { | |
int chars = layout.getLineEnd(i) - layout.getLineStart(i); | |
if (chars > maxChars) { | |
maxChars = chars; | |
maxIndex = i; | |
} | |
} | |
if (BuildConfig.DEBUG && maxIndex >= 0) { | |
CharSequence line = layout.getText().subSequence( | |
layout.getLineStart(maxIndex), | |
layout.getLineEnd(maxIndex)); | |
Log.d(TAG, "Max line: '" + line + "' (length=" + line.length() + ")"); | |
} | |
return maxChars; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright 2013 Google Inc. | |
* | |
* 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.example.android.charsperline; | |
import android.content.Context; | |
import android.content.res.TypedArray; | |
import android.util.AttributeSet; | |
import android.view.View; | |
import android.view.ViewGroup; | |
import android.widget.LinearLayout; | |
/** | |
* A simple {@link LinearLayout} subclass, useful only in the vertical orientation, that allows each | |
* child to define a maximum width using a {@link LayoutParams#maxWidth layout_maxWidth} attribute | |
* (only useful if the child's {@link ViewGroup.LayoutParams#width layout_width} is {@link | |
* ViewGroup.LayoutParams#MATCH_PARENT}). | |
*/ | |
public class MaxWidthLinearLayout extends LinearLayout { | |
public MaxWidthLinearLayout(Context context) { | |
super(context); | |
} | |
public MaxWidthLinearLayout(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
} | |
public MaxWidthLinearLayout(Context context, AttributeSet attrs, int defStyle) { | |
super(context, attrs, defStyle); | |
} | |
/** | |
* Temporarily assign a new {@link ViewGroup.LayoutParams#width} to the maximum width if the | |
* child would normally exceed the maximum width. | |
*/ | |
private void assignTemporaryChildWidthDuringMeasure(View child, int parentWidthMeasureSpec) { | |
LayoutParams lp = (LayoutParams) child.getLayoutParams(); | |
assert lp != null; | |
int availableWidth = MeasureSpec.getSize(parentWidthMeasureSpec); | |
if (lp.width == LayoutParams.MATCH_PARENT && availableWidth > lp.maxWidth) { | |
lp.oldLayoutWidth = LayoutParams.MATCH_PARENT; | |
lp.width = Math.min(lp.maxWidth, availableWidth); | |
} | |
} | |
/** | |
* Revert any changes caused by {@link #assignTemporaryChildWidthDuringMeasure(android.view.View, | |
* int)}. | |
*/ | |
private void revertChildWidthDuringMeasure(View child) { | |
LayoutParams lp = (LayoutParams) child.getLayoutParams(); | |
assert lp != null; | |
if (lp.oldLayoutWidth != Integer.MIN_VALUE) { | |
lp.width = lp.oldLayoutWidth; | |
} | |
} | |
@Override | |
protected void measureChild(View child, int parentWidthMeasureSpec, | |
int parentHeightMeasureSpec) { | |
assignTemporaryChildWidthDuringMeasure(child, parentWidthMeasureSpec); | |
super.measureChild(child, parentWidthMeasureSpec, parentHeightMeasureSpec); | |
revertChildWidthDuringMeasure(child); | |
} | |
@Override | |
protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, | |
int widthUsed, int parentHeightMeasureSpec, int heightUsed) { | |
assignTemporaryChildWidthDuringMeasure(child, parentWidthMeasureSpec); | |
super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed, | |
parentHeightMeasureSpec, heightUsed); | |
revertChildWidthDuringMeasure(child); | |
} | |
@Override | |
protected MaxWidthLinearLayout.LayoutParams generateDefaultLayoutParams() { | |
return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); | |
} | |
@Override | |
public MaxWidthLinearLayout.LayoutParams generateLayoutParams(AttributeSet attrs) { | |
return new MaxWidthLinearLayout.LayoutParams(getContext(), attrs); | |
} | |
@Override | |
protected LinearLayout.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) { | |
return new MaxWidthLinearLayout.LayoutParams(lp); | |
} | |
@Override | |
protected boolean checkLayoutParams(ViewGroup.LayoutParams lp) { | |
return lp instanceof MaxWidthLinearLayout.LayoutParams; | |
} | |
/** | |
* Provides additional layout params (specifically {@link #maxWidth layout_maxWidth}) for | |
* children of {@link MaxWidthLinearLayout}. | |
*/ | |
public static class LayoutParams extends LinearLayout.LayoutParams { | |
private int maxWidth; | |
private int oldLayoutWidth = Integer.MIN_VALUE; // used to store old lp.width during measure | |
public LayoutParams(Context c, AttributeSet attrs) { | |
super(c, attrs); | |
TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.MaxWidthLinearLayout_Layout); | |
assert a != null; | |
maxWidth = a.getLayoutDimension( | |
R.styleable.MaxWidthLinearLayout_Layout_layout_maxWidth, Integer.MAX_VALUE); | |
} | |
public LayoutParams(int width, int height) { | |
super(width, height); | |
} | |
public LayoutParams(int width, int height, int gravity) { | |
super(width, height, gravity); | |
} | |
public LayoutParams(ViewGroup.LayoutParams source) { | |
super(source); | |
} | |
public LayoutParams(MarginLayoutParams source) { | |
super(source); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- | |
Copyright 2013 Google Inc. | |
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. | |
--> | |
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:app="http://schemas.android.com/apk/res-auto" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent"> | |
<ScrollView | |
android:layout_width="match_parent" | |
android:layout_height="match_parent"> | |
<com.example.android.charsperline.MaxWidthLinearLayout | |
android:id="@+id/container" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:gravity="center_horizontal" | |
android:paddingBottom="48dp" | |
android:orientation="vertical"> | |
<TextView | |
android:id="@+id/text" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:layout_margin="16dp" | |
android:text="@string/lorem_ipsum" | |
android:textSize="18sp" | |
android:lineSpacingMultiplier="1.1" | |
android:fontFamily="sans-serif-light" | |
app:layout_maxWidth="400sp" /> | |
</com.example.android.charsperline.MaxWidthLinearLayout> | |
</ScrollView> | |
<TextView android:id="@+id/status" | |
android:layout_width="match_parent" | |
android:layout_height="48dp" | |
android:layout_gravity="bottom" | |
android:gravity="center" | |
android:background="#d000" | |
android:textSize="16sp" | |
android:fontFamily="sans-serif-condensed" | |
android:textStyle="bold|italic" /> | |
</FrameLayout> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- | |
Copyright 2013 Google Inc. | |
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. | |
--> | |
<resources> | |
<declare-styleable name="MaxWidthLinearLayout_Layout"> | |
<attr name="layout_maxWidth" format="dimension" /> | |
</declare-styleable> | |
</resources> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment