編輯:關於Android編程
在國內很多應用中,也可以看到這種效果的使用場景。如豌豆莢的詳情頁:
一、項目使用
(1).在工程的build.gradle文件中添加項目引用。
該項目較簡單,java代碼部分只有ExpandableTextView.java一個文件。
dependencies { compile 'com.ms-square:expandableTextView:0.1.4' }(2).在布局中添加如下代碼。
ExpandableTextView支持使用自定義屬性。對應的attrs.xml文件及屬性釋義如下。
(3).添加Java代碼。
ExpandableTextView expandableTextView = (ExpandableTextView) rootView.findViewById(R.id.expand_text_view); // 設置顯示內容 expandableTextView.setText(""); // 設置狀態監聽 expandableTextView.setOnExpandStateChangeListener(new ExpandableTextView.OnExpandStateChangeListener() { @Override public void onExpandStateChanged(TextView textView, boolean isExpanded) { } });
ExpandableTextView繼承自LinearLayout類,實現了OnClickListener接口,監聽自身的點擊事件,處理“展開”和“收起”。
public class ExpandableTextView extends LinearLayout implements View.OnClickListener { }
// 默認行數 private static final int MAX_COLLAPSED_LINES = 8; // 默認動畫時長 private static final int DEFAULT_ANIM_DURATION = 300; // 動畫啟動時TextView的默認透明度 private static final float DEFAULT_ANIM_ALPHA_START = 0.7f; // 顯示內容的TextView protected TextView mTv; // 箭頭按鈕ImageButton protected ImageButton mButton; // 是否需要重新布局。當調用了setText()方法後,該值置為true private boolean mRelayout; // 默認TextView處於收起狀態 private boolean mCollapsed = true; // 收起狀態下的整個View的高度 private int mCollapsedHeight; // TextView整個文本的高度 private int mTextHeightWithMaxLines; // 收起狀態下的最大顯示行數 private int mMaxCollapsedLines; // TextView的bottomMargin private int mMarginBetweenTxtAndBottom; // 箭頭按鈕的展開圖標 private Drawable mExpandDrawable; // 箭頭按鈕的收起圖標 private Drawable mCollapseDrawable; // 動畫執行時長 private int mAnimationDuration; // 動畫啟動時顯示內容的透明度 private float mAnimAlphaStart; // 是否正在執行動畫 private boolean mAnimating; // 狀態改變的監聽 private OnExpandStateChangeListener mListener; // 如果是在ListView中,需要使用到mCollapsedStatus和mPosition,保存當前position的展開或收起狀態 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); } 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); mExpandDrawable = typedArray.getDrawable(R.styleable.ExpandableTextView_expandDrawable); mCollapseDrawable = typedArray.getDrawable(R.styleable.ExpandableTextView_collapseDrawable); if (mExpandDrawable == null) { mExpandDrawable = getDrawable(getContext(), R.drawable.ic_expand_more_black_12dp); } if (mCollapseDrawable == null) { mCollapseDrawable = getDrawable(getContext(), R.drawable.ic_expand_less_black_12dp); } typedArray.recycle(); // 強制把方向設置為垂直 setOrientation(LinearLayout.VERTICAL); // 默認不顯示 setVisibility(GONE); }
當xml布局文件加載完成之後,後執行onFinishInflate()方法,在這裡完成View的初始化。
@Override protected void onFinishInflate() { findViews(); } private void findViews() { mTv = (TextView) findViewById(R.id.expandable_text); mTv.setOnClickListener(this); mButton = (ImageButton) findViewById(R.id.expand_collapse); mButton.setImageDrawable(mCollapsed ? mExpandDrawable : mCollapseDrawable); mButton.setOnClickListener(this); }
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // 如果沒有改變顯示內容,或者顯示內容為空,執行super.onMeasure()並返回 if (!mRelayout || getVisibility() == View.GONE) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); return; } mRelayout = false; // 先隱藏箭頭按鈕,將文字最大顯示行數設置到最大,後面再根據測量情況修改 mButton.setVisibility(View.GONE); mTv.setMaxLines(Integer.MAX_VALUE); // 測量 super.onMeasure(widthMeasureSpec, heightMeasureSpec); // 如果內容未超出限定的最大顯示行數,直接返回。在這種情況下,無需展開和收起。 if (mTv.getLineCount() <= mMaxCollapsedLines) { return; } // 計算TextView的真實高度並保存 mTextHeightWithMaxLines = getRealTextViewHeight(mTv); // 限定TextView的最大行數,並將箭頭按鈕顯示出來 if (mCollapsed) { mTv.setMaxLines(mMaxCollapsedLines); } mButton.setVisibility(View.VISIBLE); // 再次重新測量 super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (mCollapsed) { mTv.post(new Runnable() { @Override public void run() { // TextView的bottomMargin mMarginBetweenTxtAndBottom = getHeight() - mTv.getHeight(); } }); // 保存收起狀態下的整個View的高度 mCollapsedHeight = getMeasuredHeight(); } } // 獲取TextView的真實高度,即內容展開時的高度 private static int getRealTextViewHeight(@NonNull TextView textView) { int textHeight = textView.getLayout().getLineTop(textView.getLineCount()); int padding = textView.getCompoundPaddingTop() + textView.getCompoundPaddingBottom(); return textHeight + padding; }
// 實現了展開/收起功能的動畫 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) { // 計算在執行動畫時,逐漸變化產生的整個View的新高度 final int newHeight = (int)((mEndHeight - mStartHeight) * interpolatedTime + mStartHeight); // 修改TextView的最大高度 mTv.setMaxHeight(newHeight - mMarginBetweenTxtAndBottom); // 如果初始設置了透明度,修改TextView的透明度,直到alpha==1完全不透明 if (Float.compare(mAnimAlphaStart, 1.0f) != 0) { applyAlphaAnimation(mTv, mAnimAlphaStart + interpolatedTime * (1.0f - mAnimAlphaStart)); } // 修改整個View的高度 mTargetView.getLayoutParams().height = newHeight; mTargetView.requestLayout(); } } // 改變View的透明度 @TargetApi(Build.VERSION_CODES.HONEYCOMB) private static void applyAlphaAnimation(View view, float alpha) { if (isPostHoneycomb()) { // setAlpha()方法是Android3.0以上才有的api view.setAlpha(alpha); } else { // 在Android3.0以下,使用AlphaAnimation並將Duration設置為0來實現 AlphaAnimation alphaAnimation = new AlphaAnimation(alpha, alpha); alphaAnimation.setDuration(0); alphaAnimation.setFillAfter(true); view.startAnimation(alphaAnimation); } } private static boolean isPostHoneycomb() { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB; }
@Override public void onClick(View view) { // 文字內容太短,無需折疊時,箭頭按鈕是隱藏的。這時直接返回。 if (mButton.getVisibility() != View.VISIBLE) { return; } // 將變量mCollapsed和mButton顯示的圖片賦值為相反 mCollapsed = !mCollapsed; mButton.setImageDrawable(mCollapsed ? mExpandDrawable : mCollapseDrawable); // 將當前位置的狀態保存起來,在ListView中需要使用 if (mCollapsedStatus != null) { mCollapsedStatus.put(mPosition, mCollapsed); } // 標記動畫開始 mAnimating = true; Animation animation; if (mCollapsed) { // “收起”動畫,從當前高度開始,降低到收起狀態下的高度mCollapsedHeight animation = new ExpandCollapseAnimation(this, getHeight(), mCollapsedHeight); } else { // “展開”動畫,在當前整個View高度的基礎上,增加TextView變化的高度(mTextHeightWithMaxLines - mTv.getHeight()) animation = new ExpandCollapseAnimation(this, getHeight(), getHeight() + mTextHeightWithMaxLines - mTv.getHeight()); } animation.setFillAfter(true); animation.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { // 動畫開始,改變TextView的透明度 applyAlphaAnimation(mTv, mAnimAlphaStart); } @Override public void onAnimationEnd(Animation animation) { // 清除動畫,防止applyTransformation()重復執行 clearAnimation(); // 標記動畫結束 mAnimating = false; // 通知listener if (mListener != null) { mListener.onExpandStateChanged(mTv, !mCollapsed); } } @Override public void onAnimationRepeat(Animation animation) { } }); // 清除之前的動畫,開啟新的動畫 clearAnimation(); startAnimation(animation); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { // 動畫執行期間,攔截掉觸摸事件,不傳遞給子View return mAnimating; }
// 設置顯示內容 public void setText(@Nullable CharSequence text) { mRelayout = true; mTv.setText(text); // 內容不為空時,才會顯示 setVisibility(TextUtils.isEmpty(text) ? View.GONE : View.VISIBLE); } // 設置顯示內容,在ListView等存在item復用的情況下需要使用該方法 public void setText(@Nullable CharSequence text, @NonNull SparseBooleanArray collapsedStatus, int position) { mCollapsedStatus = collapsedStatus; mPosition = position; boolean isCollapsed = collapsedStatus.get(position, true); clearAnimation(); mCollapsed = isCollapsed; mButton.setImageDrawable(mCollapsed ? mExpandDrawable : mCollapseDrawable); setText(text); getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT; requestLayout(); }
public void setOnExpandStateChangeListener(@Nullable OnExpandStateChangeListener listener) { mListener = listener; } // 狀態改變的監聽器 public interface OnExpandStateChangeListener { /** * 當展開或收起的動畫執行完畢之後,該方法被回調 * @param textView - 展開或收起的TextView * @param isExpanded - 如果文字被展開,該值為true;否則為false */ void onExpandStateChanged(TextView textView, boolean isExpanded); }
@Override public void setOrientation(int orientation){ if(LinearLayout.HORIZONTAL == orientation){ throw new IllegalArgumentException("ExpandableTextView only supports Vertical Orientation."); } super.setOrientation(orientation); }
Android 中使用代碼動態布局 本文介紹在android中使用代碼動態布局,有時候根據不同的需求,比如需要根據服務器上的條目個數來決定app中頁面布局控件(
一、在JavaEE項目中搭建環境 1. 導入相關jar包 2. 搭建相關的包和類 UserDao: UserDaoImpl: JsonServlet
本文是在我的文章android圖片處理,讓圖片變成圓形 的基礎上繼續寫的,可以去看看,直接看也沒關系,也能看懂 1、首先在res文件夾下創建一個名字為anim的
概述 RSA是目前最有影響力的公鑰加密算法,該算法基於一個十分簡單的數論事實:將兩個大素數相乘十分容易,但那時想要對其乘積進行因式分解卻極其困 難,因此可以