提交 ca9876b1 编写于 作者: 门心叼龙's avatar 门心叼龙

add ExpandableTextView

上级 87a0243f
......@@ -6,6 +6,7 @@ import com.yesway.android.net.ApiManager;
import com.yesway.android.net.dto.response.LoginResponse;
import com.yesway.android.net.http.Response;
import com.yesway.android.net.model.IUserModel;
import com.yesway.android.view.ExpandableTextView;
import android.content.Intent;
import android.os.Bundle;
......@@ -20,15 +21,8 @@ public class MainActivity extends BaseActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.btn).setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
Intent intent = new Intent("android.intent.action.second_activity");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
});
ExpandableTextView expandableTextView = findViewById(R.id.expand_text_view);
expandableTextView.setText("我们为全球首个人工智能区块链数字资产交易平台(全球前十)提供全面技术支持服务\n" + "公司以区块链技术开发应用为核心业务方向,获得一线资本千万美元的投资,全力打造全球区块链行业中,安全、透明的区块链资产技术服务平台是我们的企业使命");
}
@Override
......
/*
* Copyright (C) 2011 The Android Open Source Project Copyright 2014 Manabu Shimobe
*
* 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.yesway.android.view;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Handler;
import android.support.annotation.DrawableRes;
import android.support.annotation.IdRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.SparseBooleanArray;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.yesway.android.R;
/**
* 默认展开状态: ExpandableTextView.expandView(); ExpandableTextView.showToogleView(false);
*/
public class ExpandableTextView extends LinearLayout implements View.OnClickListener {
private static final String TAG = ExpandableTextView.class.getSimpleName();
private static final int EXPAND_INDICATOR_IMAGE_BUTTON = 0;
private static final int EXPAND_INDICATOR_TEXT_VIEW = 1;
private static final int DEFAULT_TOGGLE_TYPE = EXPAND_INDICATOR_IMAGE_BUTTON;
/* The default number of lines */
private static final int MAX_COLLAPSED_LINES = 8;
/* The default animation duration */
private static final int DEFAULT_ANIM_DURATION = 300;
/* The default alpha value when the animation starts */
private static final float DEFAULT_ANIM_ALPHA_START = 0.7f;
protected TextView mTv;
protected View mToggleView; // View to expand/collapse
private boolean mRelayout;
private boolean mCollapsed = true; // Show short version as default.
private int mCollapsedHeight;
private int mTextHeightWithMaxLines;
private int mMaxCollapsedLines;
private int mMarginBetweenTxtAndBottom;
private ExpandIndicatorController mExpandIndicatorController;
private int mAnimationDuration;
private float mAnimAlphaStart;
private boolean mAnimating;
@IdRes
private int mExpandableTextId = R.id.expandable_text;
@IdRes
private int mExpandCollapseToggleId = R.id.expand_collapse;
private boolean mExpandToggleOnTextClick;
/* Listener for callback */
private OnExpandStateChangeListener mListener;
/* For saving collapsed status when used in ListView */
private SparseBooleanArray mCollapsedStatus;
private int mPosition;
public ExpandableTextView(Context context) {
this(context, null);
}
public ExpandableTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public ExpandableTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs);
}
@Override
public void setOrientation(int orientation) {
if (LinearLayout.HORIZONTAL == orientation) {
throw new IllegalArgumentException("ExpandableTextView only supports Vertical Orientation.");
}
super.setOrientation(orientation);
}
@Override
public void onClick(View view) {
if (mToggleView.getVisibility() != View.VISIBLE) {
return;
}
mCollapsed = !mCollapsed;
mExpandIndicatorController.changeState(mCollapsed);
if (mCollapsedStatus != null) {
mCollapsedStatus.put(mPosition, mCollapsed);
}
// mark that the animation is in progress
mAnimating = true;
Animation animation;
if (mCollapsed) {
animation = new ExpandCollapseAnimation(this, getHeight(), mCollapsedHeight);
} else {
animation = new ExpandCollapseAnimation(this, getHeight(),
getHeight() + mTextHeightWithMaxLines - mTv.getHeight());
}
animation.setFillAfter(true);
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
applyAlphaAnimation(mTv, mAnimAlphaStart);
}
@Override
public void onAnimationEnd(Animation animation) {
// clear animation here to avoid repeated applyTransformation() calls
clearAnimation();
// clear the animation flag
mAnimating = false;
// notify the listener
if (mListener != null) {
mListener.onExpandStateChanged(mTv, !mCollapsed);
}
}
@Override
public void onAnimationRepeat(Animation animation) {}
});
clearAnimation();
startAnimation(animation);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// while an animation is in progress, intercept all the touch events to children to
// prevent extra clicks during the animation
return mAnimating;
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
findViews();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// If no change, measure and return
if (!mRelayout || getVisibility() == View.GONE) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
mRelayout = false;
// Setup with optimistic case
// i.e. Everything fits. No button needed
mToggleView.setVisibility(View.GONE);
mTv.setMaxLines(Integer.MAX_VALUE);
// Measure
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// If the text fits in collapsed mode, we are done.
if (mTv.getLineCount() <= mMaxCollapsedLines) {
return;
}
// Saves the text height w/ max lines
mTextHeightWithMaxLines = getRealTextViewHeight(mTv);
// Doesn't fit in collapsed mode. Collapse text view as needed. Show
// button.
if (mCollapsed) {
mTv.setMaxLines(mMaxCollapsedLines);
}
mToggleView.setVisibility(View.VISIBLE);
// Re-measure with new setup
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (mCollapsed) {
// Gets the margin between the TextView's bottom and the ViewGroup's bottom
mTv.post(new Runnable() {
@Override
public void run() {
mMarginBetweenTxtAndBottom = getHeight() - mTv.getHeight();
}
});
// Saves the collapsed height of this ViewGroup
mCollapsedHeight = getMeasuredHeight();
}
}
public void setOnExpandStateChangeListener(@Nullable OnExpandStateChangeListener listener) {
mListener = listener;
}
public void setText(@Nullable CharSequence text) {
mRelayout = true;
mTv.setText(text);
setVisibility(TextUtils.isEmpty(text) ? View.GONE : View.VISIBLE);
clearAnimation();
getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
requestLayout();
}
public void setText(@Nullable CharSequence text, @NonNull SparseBooleanArray collapsedStatus,
int position) {
mCollapsedStatus = collapsedStatus;
mPosition = position;
boolean isCollapsed = collapsedStatus.get(position, true);
clearAnimation();
mCollapsed = isCollapsed;
mExpandIndicatorController.changeState(mCollapsed);
setText(text);
}
@Nullable
public CharSequence getText() {
if (mTv == null) {
return "";
}
return mTv.getText();
}
private void init(AttributeSet attrs) {
TypedArray typedArray =
getContext().obtainStyledAttributes(attrs, R.styleable.ExpandableTextView);
mMaxCollapsedLines =
typedArray.getInt(R.styleable.ExpandableTextView_maxCollapsedLines, MAX_COLLAPSED_LINES);
mAnimationDuration =
typedArray.getInt(R.styleable.ExpandableTextView_animDuration, DEFAULT_ANIM_DURATION);
mAnimAlphaStart = typedArray.getFloat(R.styleable.ExpandableTextView_animAlphaStart,
DEFAULT_ANIM_ALPHA_START);
mExpandableTextId = typedArray.getResourceId(R.styleable.ExpandableTextView_expandableTextId,
R.id.expandable_text);
mExpandCollapseToggleId = typedArray
.getResourceId(R.styleable.ExpandableTextView_expandCollapseToggleId, R.id.expand_collapse);
mExpandToggleOnTextClick =
typedArray.getBoolean(R.styleable.ExpandableTextView_expandToggleOnTextClick, true);
mExpandIndicatorController = setupExpandToggleController(getContext(), typedArray);
typedArray.recycle();
// enforces vertical orientation
setOrientation(LinearLayout.VERTICAL);
// default visibility is gone
setVisibility(GONE);
}
private void findViews() {
mTv = (TextView) findViewById(mExpandableTextId);
if (mExpandToggleOnTextClick) {
mTv.setOnClickListener(this);
} else {
mTv.setOnClickListener(null);
}
mToggleView = findViewById(mExpandCollapseToggleId);
mExpandIndicatorController.setView(mToggleView);
mExpandIndicatorController.changeState(mCollapsed);
mToggleView.setOnClickListener(this);
}
private static boolean isPostHoneycomb() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
}
private static boolean isPostLolipop() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private static void applyAlphaAnimation(View view, float alpha) {
if (isPostHoneycomb()) {
view.setAlpha(alpha);
} else {
AlphaAnimation alphaAnimation = new AlphaAnimation(alpha, alpha);
// make it instant
alphaAnimation.setDuration(0);
alphaAnimation.setFillAfter(true);
view.startAnimation(alphaAnimation);
}
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private static Drawable getDrawable(@NonNull Context context, @DrawableRes int resId) {
Resources resources = context.getResources();
if (isPostLolipop()) {
return resources.getDrawable(resId, context.getTheme());
} else {
return resources.getDrawable(resId);
}
}
private static int getRealTextViewHeight(@NonNull TextView textView) {
int textHeight = textView.getLayout().getLineTop(textView.getLineCount());
int padding = textView.getCompoundPaddingTop() + textView.getCompoundPaddingBottom();
return textHeight + padding;
}
private ExpandIndicatorController setupExpandToggleController(@NonNull Context context,
TypedArray typedArray) {
final int expandToggleType =
typedArray.getInt(R.styleable.ExpandableTextView_expandToggleType, DEFAULT_TOGGLE_TYPE);
final ExpandIndicatorController expandIndicatorController;
switch (expandToggleType) {
case EXPAND_INDICATOR_IMAGE_BUTTON:
Drawable expandDrawable =
typedArray.getDrawable(R.styleable.ExpandableTextView_expandIndicator);
Drawable collapseDrawable =
typedArray.getDrawable(R.styleable.ExpandableTextView_collapseIndicator);
if (expandDrawable == null) {
expandDrawable = getDrawable(context, R.mipmap.expend_btn);
}
if (collapseDrawable == null) {
collapseDrawable = getDrawable(context, R.mipmap.reduce_btn);
}
expandIndicatorController =
new ImageButtonExpandController(expandDrawable, collapseDrawable);
break;
case EXPAND_INDICATOR_TEXT_VIEW:
String expandText = typedArray.getString(R.styleable.ExpandableTextView_expandIndicator);
String collapseText =
typedArray.getString(R.styleable.ExpandableTextView_collapseIndicator);
expandIndicatorController = new TextViewExpandController(expandText, collapseText);
break;
default:
throw new IllegalStateException(
"Must be of enum: ExpandableTextView_expandToggleType, one of EXPAND_INDICATOR_IMAGE_BUTTON or EXPAND_INDICATOR_TEXT_VIEW.");
}
return expandIndicatorController;
}
class ExpandCollapseAnimation extends Animation {
private final View mTargetView;
private final int mStartHeight;
private final int mEndHeight;
public ExpandCollapseAnimation(View view, int startHeight, int endHeight) {
mTargetView = view;
mStartHeight = startHeight;
mEndHeight = endHeight;
setDuration(mAnimationDuration);
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
final int newHeight = (int) ((mEndHeight - mStartHeight) * interpolatedTime + mStartHeight);
mTv.setMaxHeight(newHeight - mMarginBetweenTxtAndBottom);
if (Float.compare(mAnimAlphaStart, 1.0f) != 0) {
applyAlphaAnimation(mTv, mAnimAlphaStart + interpolatedTime * (1.0f - mAnimAlphaStart));
}
mTargetView.getLayoutParams().height = newHeight;
mTargetView.requestLayout();
}
@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
}
@Override
public boolean willChangeBounds() {
return true;
}
}
public interface OnExpandStateChangeListener {
/**
* Called when the expand/collapse animation has been finished
*
* @param textView - TextView being expanded/collapsed
* @param isExpanded - true if the TextView has been expanded
*/
void onExpandStateChanged(TextView textView, boolean isExpanded);
}
interface ExpandIndicatorController {
void changeState(boolean collapsed);
void setView(View toggleView);
void showView(boolean isshow);
}
class ImageButtonExpandController implements ExpandIndicatorController {
private final Drawable mExpandDrawable;
private final Drawable mCollapseDrawable;
private ImageButton mImageButton;
public ImageButtonExpandController(Drawable expandDrawable, Drawable collapseDrawable) {
mExpandDrawable = expandDrawable;
mCollapseDrawable = collapseDrawable;
}
@Override
public void changeState(boolean collapsed) {
mImageButton.setImageDrawable(collapsed ? mExpandDrawable : mCollapseDrawable);
}
@Override
public void setView(View toggleView) {
mImageButton = (ImageButton) toggleView;
}
@Override
public void showView(final boolean isshow) {
if (mImageButton != null) {
new Handler().post(new Runnable() {
@Override
public void run() {
mImageButton.clearAnimation();
mImageButton.setVisibility(isshow ? View.VISIBLE : View.GONE);
}
});
}
}
}
static class TextViewExpandController implements ExpandIndicatorController {
private final String mExpandText;
private final String mCollapseText;
private TextView mTextView;
public TextViewExpandController(String expandText, String collapseText) {
mExpandText = expandText;
mCollapseText = collapseText;
}
@Override
public void changeState(boolean collapsed) {
mTextView.setText(collapsed ? mExpandText : mCollapseText);
}
@Override
public void setView(View toggleView) {
mTextView = (TextView) toggleView;
}
@Override
public void showView(boolean isshow) {
}
}
public void showToogleView(boolean isshow) {
if (mExpandIndicatorController != null) {
mExpandIndicatorController.showView(isshow);
}
}
public void expandView() {
mCollapsed = false;
requestLayout();
}
}
package com.yesway.android.view;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.MotionEvent;
/**
* Description: <RecyclerView空白区域点击监听><br>
* Author: gxl<br>
* Date: 2018/8/24<br>
* Version: V1.0.0<br>
* Update: <br>
*/
public class TouchyRecyclerView extends RecyclerView {
private OnNoChildClickListener listener;
public TouchyRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public interface OnNoChildClickListener {
public void onNoChildClick();
}
public void setOnNoChildClickListener(OnNoChildClickListener listener) {
this.listener = listener;
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN
&& findChildViewUnder(event.getX(), event.getY()) == null) {
if (listener != null) {
listener.onNoChildClick();
}
}
return super.dispatchTouchEvent(event);
}
}
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#F0F0F0"
tools:context="com.yesway.android.MainActivity">
android:orientation="vertical">
<Button
android:id="@+id/btn"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp"
android:text="TEST"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:layout_editor_absoluteX="32dp"/>
<com.yesway.android.view.MagicTextView
android:textSize="78dp"
android:textColor="#2a2a2a"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textStyle="bold"
android:padding="10dp"
app:innerShadowDy="5dp"
android:text="1245"
android:textColor="#2a2a2a"
android:textSize="78dp"
android:textStyle="bold"
app:innerShadowColor="#ff0f"
app:innerShadowDy="5dp"
app:innerShadowRadius="1dp"
app:outerShadowDy="3dp"
app:outerShadowColor="#FF0088ff"
app:outerShadowDy="3dp"
app:outerShadowRadius="10dp"
app:strokeColor="#FFff0000"
app:strokeJoinStyle="miter"
app:strokeWidth="5dp"
android:text="1245"
tools:ignore="MissingPrefix"/>
app:strokeWidth="5dp"/>
<com.yesway.android.view.ExpandableTextView
android:id="@+id/expand_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:animAlphaStart="1"
app:expandToggleOnTextClick="false"
app:maxCollapsedLines="5"
>
<TextView
android:id="@id/expandable_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-light"
android:textColor="#2A2A2A"
android:textSize="16sp"
/>
</android.support.constraint.ConstraintLayout>
<ImageButton
android:id="@id/expand_collapse"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left|bottom"
android:background="@android:color/transparent"/>
</com.yesway.android.view.ExpandableTextView>
</LinearLayout>
\ No newline at end of file
......@@ -30,4 +30,18 @@
<enum name="round" value="2" />
</attr>
</declare-styleable>
<declare-styleable name="ExpandableTextView">
<attr name="maxCollapsedLines" format="integer"/>
<attr name="animDuration" format="integer"/>
<attr name="animAlphaStart" format="float"/>
<attr name="expandIndicator" format="reference"/>
<attr name="collapseIndicator" format="reference"/>
<attr name="expandToggleType" format="enum">
<enum name="ImageButton" value="0"/>
<enum name="TextView" value="1"/>
</attr>
<attr name="expandableTextId" format="reference"/>
<attr name="expandCollapseToggleId" format="reference"/>
<attr name="expandToggleOnTextClick" format="boolean"/>
</declare-styleable>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item type="id" name="glide_tag" />
<item type="id" name="expandable_text"/>
<item type="id" name="expand_collapse"/>
</resources>
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册