可以展开和收起的的LinearLayout
package com.loaderman.expandablelinearlayout; import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
/**
* 可以展开的LinearLayout
*/
public class ExpandableLinearLayout extends LinearLayout implements View.OnClickListener { private static final String TAG = ExpandableLinearLayout.class.getSimpleName(); private TextView tvTip;
private ImageView ivArrow; private boolean isExpand = false;//是否是展开状态,默认是隐藏 private int defaultItemCount;//一开始展示的条目数
private String expandText;//待展开显示的文字
private String hideText;//待隐藏显示的文字
private boolean useDefaultBottom;//是否使用默认的底部,默认为true使用默认的底部
private boolean hasBottom;//是否已经有底部,默认为false,没有
private View bottomView;
private float fontSize;
private int textColor;
private int arrowResId; public ExpandableLinearLayout(Context context) {
this(context, null);
} public ExpandableLinearLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
} public ExpandableLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr); TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ExpandableLinearLayout);
defaultItemCount = ta.getInt(R.styleable.ExpandableLinearLayout_defaultItemCount, 2);
expandText = ta.getString(R.styleable.ExpandableLinearLayout_expandText);
hideText = ta.getString(R.styleable.ExpandableLinearLayout_hideText);
fontSize = ta.getDimension(R.styleable.ExpandableLinearLayout_tipTextSize, UIUtils.sp2px(context, 14));
textColor = ta.getColor(R.styleable.ExpandableLinearLayout_tipTextColor, Color.parseColor("#666666"));
arrowResId = ta.getResourceId(R.styleable.ExpandableLinearLayout_arrowDownImg, R.mipmap.arrow_down);
useDefaultBottom = ta.getBoolean(R.styleable.ExpandableLinearLayout_useDefaultBottom, true);
ta.recycle(); setOrientation(VERTICAL);
} /**
* 渲染完成时初始化默认底部view
*/
@Override
protected void onFinishInflate() {
super.onFinishInflate();
findViews();
} /**
* 初始化底部view
*/
private void findViews() {
bottomView = View.inflate(getContext(), R.layout.item_ell_bottom, null);
ivArrow = (ImageView) bottomView.findViewById(R.id.iv_arrow); tvTip = (TextView) bottomView.findViewById(R.id.tv_tip);
tvTip.getPaint().setTextSize(fontSize);
tvTip.setTextColor(textColor);
ivArrow.setImageResource(arrowResId); bottomView.setOnClickListener(this);
} public void addItem(View view) {
int childCount = getChildCount();
if (!useDefaultBottom){
//如果不使用默认底部
addView(view);
if (childCount > defaultItemCount){
hide();
}
return;
} //使用默认底部
if (!hasBottom) {
//如果还没有底部
addView(view);
} else {
addView(view, childCount - 2);//插在底部之前
}
refreshUI(view);
} @Override
public void setOrientation(int orientation) {
if (LinearLayout.HORIZONTAL == orientation) {
throw new IllegalArgumentException("ExpandableTextView only supports Vertical Orientation.");
}
super.setOrientation(orientation);
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int childCount = getChildCount();
Log.i(TAG, "childCount: " + childCount);
justToAddBottom(childCount);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
} /**
* 判断是否要添加底部
* @param childCount
*/
private void justToAddBottom(int childCount) {
if (childCount > defaultItemCount) {
if (useDefaultBottom && !hasBottom) {
//要使用默认底部,并且还没有底部
addView(bottomView);//添加底部
hide();
hasBottom = true;
}
}
} /**
* 刷新UI
*
* @param view
*/
private void refreshUI(View view) {
int childCount = getChildCount();
if (childCount > defaultItemCount) {
if (childCount - defaultItemCount == 1) {
//刚超过默认,判断是否要添加底部
justToAddBottom(childCount);
}
view.setVisibility(GONE);//大于默认数目的先隐藏
}
} /**
* 展开
*/
private void expand() {
for (int i = defaultItemCount; i < getChildCount(); i++) {
//从默认显示条目位置以下的都显示出来
View view = getChildAt(i);
view.setVisibility(VISIBLE);
}
} /**
* 收起
*/
private void hide() {
int endIndex = useDefaultBottom ? getChildCount() - 1 : getChildCount();//如果是使用默认底部,则结束的下标是到底部之前,否则则全部子条目都隐藏
for (int i = defaultItemCount; i < endIndex; i++) {
//从默认显示条目位置以下的都隐藏
View view = getChildAt(i);
view.setVisibility(GONE);
}
} // 箭头的动画
private void doArrowAnim() {
if (isExpand) {
// 当前是展开,将执行收起,箭头由上变为下
ObjectAnimator.ofFloat(ivArrow, "rotation", -180, 0).start();
} else {
// 当前是收起,将执行展开,箭头由下变为上
ObjectAnimator.ofFloat(ivArrow, "rotation", 0, 180).start();
}
} @Override
public void onClick(View v) {
toggle();
} public void toggle() {
if (isExpand) {
hide();
tvTip.setText(expandText);
} else {
expand();
tvTip.setText(hideText);
}
doArrowAnim();
isExpand = !isExpand; //回调
if (mListener != null){
mListener.onStateChanged(isExpand);
}
} private OnStateChangeListener mListener; /**
* 定义状态改变接口
*/
public interface OnStateChangeListener {
void onStateChanged(boolean isExpanded);
} public void setOnStateChangeListener(OnStateChangeListener mListener) {
this.mListener = mListener;
}
}
UIUtil.java
package com.loaderman.expandablelinearlayout; import android.content.Context; public class UIUtils {
/**
* dip-->px
*/
public static int dip2Px(Context context,int dip) {
// px/dip = density;
// density = dpi/160
// 320*480 density = 1 1px = 1dp
// 1280*720 density = 2 2px = 1dp float density = context.getResources().getDisplayMetrics().density;
int px = (int) (dip * density + 0.5f);
return px;
} /**
* 将sp值转换为px值,保证文字大小不变
*
* @param spValue
* @return
*/
public static int sp2px(Context context,float spValue) {
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (spValue * fontScale + 0.5f);
}
}
attr.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ExpandableLinearLayout">
<!--默认显示的条目数-->
<attr name="defaultItemCount" format="integer" />
<!--提示文字的大小-->
<attr name="tipTextSize" format="dimension" />
<!--字体颜色-->
<attr name="tipTextColor" format="color"/>
<!--待展开的文字提示-->
<attr name="expandText" format="string" />
<!--待收起时的文字提示-->
<attr name="hideText" format="string" />
<!--向下的箭头的图标-->
<attr name="arrowDownImg" format="reference" />
<!--是否使用默认的底部-->
<attr name="useDefaultBottom" format="boolean" />
</declare-styleable>
</resources>
item_ell_bottom.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="10dp"
> <TextView
android:id="@+id/tv_tip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="查看更多"
/> <ImageView
android:id="@+id/iv_arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginLeft="5dp"
android:layout_toRightOf="@id/tv_tip"
/> </RelativeLayout>
ProductBean.java
package com.loaderman.expandablelinearlayout; public class ProductBean {
private String img;
private String name;
private String intro;
private String price; public ProductBean(String img, String name, String intro, String price) {
this.img = img;
this.name = name;
this.intro = intro;
this.price = price;
} public String getImg() {
return img;
} public void setImg(String img) {
this.img = img;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getIntro() {
return intro;
} public void setIntro(String intro) {
this.intro = intro;
} public String getPrice() {
return price;
} public void setPrice(String price) {
this.price = price;
}
}
MainActivity.java
package com.loaderman.expandablelinearlayout; import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView; import com.bumptech.glide.Glide; import butterknife.Bind;
import butterknife.ButterKnife; public class MainActivity extends AppCompatActivity {
@Bind(R.id.ell_product)
ExpandableLinearLayout ellProduct; private String[] imgUrls = new String[]{
"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1496728066&di=e5669ad80a241da52b03301ee0ba2749&imgtype=jpg&er=1&src=http%3A%2F%2Fimg.taopic.com%2Fuploads%2Fallimg%2F121017%2F240425-12101H2202646.jpg",
"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1496728145&di=c2ece04e1445eaf91fe3f3bf12ad1080&imgtype=jpg&er=1&src=http%3A%2F%2Fimg1.qunarzz.com%2Ftravel%2Fd6%2F1610%2F33%2F21ce9c91e70ab7b5.jpg_r_720x480x95_b2bcd2c5.jpg",
"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1496728182&di=1e06ea8b74863155b9d52736093beda8&imgtype=jpg&er=1&src=http%3A%2F%2Fe.hiphotos.baidu.com%2Fbainuo%2Fcrop%3D0%2C0%2C470%2C285%3Bw%3D470%3Bq%3D79%2Fsign%3Da8aa38e3b73533fae1f9c96e95e3d12f%2F6c224f4a20a44623b885148f9e22720e0df3d794.jpg",
"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1496133522433&di=1132cb36274a205f8ce30e21f47a37ee&imgtype=0&src=http%3A%2F%2Fi3.s2.dpfile.com%2Fpc%2Fb68a2a4316ae56373e83ce65ad7dfada%2528249x249%2529%2Fthumb.jpg",
"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1496728305&di=444bfe10c434c09043855e7a6a7f8ace&imgtype=jpg&er=1&src=http%3A%2F%2Fe.hiphotos.baidu.com%2Fbainuo%2Fcrop%3D0%2C0%2C470%2C285%3Bw%3D470%3Bq%3D99%2Fsign%3D65498f21374e251ff6b8beb89ab6e527%2F0df3d7ca7bcb0a46d662a6226c63f6246b60af6c.jpg"
}; private String[] names = new String[]{
"炒河粉",
"炒米粉",
"隆江猪脚饭",
"烧鸭饭",
"叉烧饭"
}; private String[] intros = new String[]{
"好吃又不腻",
"精选上等米粉,绝对好吃",
"隆江猪脚饭,肥而不腻,入口香爽,深受广东人民的喜爱",
"简单而美味,充满烧腊香味",
"色香味俱全"
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this); ellProduct.removeAllViews();//清除所有的子View(避免重新刷新数据时重复添加)
//添加数据
for (int i = 0; i < 5; i++) {
View view = View.inflate(this, R.layout.item_product, null);
ProductBean productBean = new ProductBean(imgUrls[i], names[i], intros[i], "12.00");
ViewHolder viewHolder = new ViewHolder(view, productBean);
viewHolder.refreshUI();
ellProduct.addItem(view);//添加子条目
}
}class ViewHolder {
@Bind(R.id.iv_img)
ImageView ivImg;
@Bind(R.id.tv_name)
TextView tvName;
@Bind(R.id.tv_intro)
TextView tvIntro;
@Bind(R.id.tv_price)
TextView tvPrice; ProductBean productBean; public ViewHolder(View view, ProductBean productBean) {
ButterKnife.bind(this, view);
this.productBean = productBean;
} private void refreshUI() {
Glide.with(MainActivity.this)
.load(productBean.getImg())
.placeholder(R.mipmap.ic_launcher)
.into(ivImg);
tvName.setText(productBean.getName());
tvIntro.setText(productBean.getIntro());
tvPrice.setText("¥" + productBean.getPrice());
}
} }
item_product.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" > <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="10dp"
> <ImageView
android:id="@+id/iv_img"
android:layout_width="100dp"
android:layout_height="80dp"
android:layout_gravity="center"
android:scaleType="centerCrop"
android:src="@mipmap/ic_launcher"
/> <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:orientation="vertical"
> <TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="隆江猪脚饭"
/> <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center"
android:orientation="horizontal"
> <TextView
android:id="@+id/tv_intro"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="特别好吃哦,带回家啊时间还是健康的贺卡上空间的挥洒健康的贺卡姐啊上课黑色的健康哈空间"
android:textColor="#9f9f9f"
/> <TextView
android:id="@+id/tv_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:drawablePadding="5dp"
android:text="12.00"
/> </LinearLayout> </LinearLayout> </LinearLayout> <View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="#D1D1D1"/> </LinearLayout>
最后添加依赖:
compile 'com.github.bumptech.glide:glide:3.7.0'
compile 'com.jakewharton:butterknife:7.0.0'
添加网络权限:
<uses-permission android:name="android.permission.INTERNET"/>
效果图:
学习来源:http://blog.csdn.net/chay_chan/article/details/72810770
可以展开和收起的的LinearLayout的更多相关文章
- 【Android】键盘的展开和收起
键盘的展开和收起主要使用到类InputMethodManager:http://developer.android.com/reference/android/view/inputmethod/Inp ...
- js 点击展开、收起
//点击展开.收起 window.onload=function(){ var current=document.getElementsByTagName('li')[0]; document.bod ...
- UITableView多层展开与收起
规则要求: tableview 有多层,类似于xcode文件目录的层级关系,每一个最开始展示的层姑且称之为根目录吧,并且,每个根目录下的层数不定. 与文件目录类似,每个目录下可以有不同层级的目录同时展 ...
- 长图的展开与收起(Android)
前言: 在app的文章中,经常会夹杂着一些特别长的长图.在阅读的时候需要滑动很久才能看图片下方的文字,因此对于长图只展示图片上面一部分,并且可以展开这个功能是很重要的. 效果: 基本思路: 利用sca ...
- jQuery实现画面的展开、收起和停止
主要用到动画效果中的三个操作 ("#id").slideDown(3000): // 后面的数字表示效果的时长 ("#id").stop(); ("# ...
- div展开与收起(鼠标点击)
效果图: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF- ...
- Silverlight自定义控件系列 – TreeView (3) 添加展开和收起事件
由于Writer嫌我文章过长,只能把上篇拆开两半了.以下是接着上篇的. 准备工作做完了,现在就要完成点击事件. 定义Expander和单击事件: 1: /// <summary> 2: / ...
- Vue:列表展开和收起(超过一定行数时显示‘查看更多’按钮)
前言:前端小白记录的一些小功能~ 公司开发中的小程序中有做任务签到的功能,这就涉及到了任务列表以及对任务列表的展开和收起功能,好了可以开始了,说多了就烦了 1.首先是css样式,因为设计稿上是超过两行 ...
- 巧妙利用before和after伪类实现文字的展开和收起
需求:一段文字,当收起的时候,显示4行,并且多余4行的部分用省略号表示,关键是在省略号前面留有空白部分来放一些图标等东西:展开的时候,全部显示. 例如下面的示例图: 收起的时候: 展开的时候: 在不用 ...
随机推荐
- Q2Day79
requests Python标准库中提供了:urllib.urllib2.httplib等模块以供Http请求,但是,它的 API 太渣了.它是为另一个时代.另一个互联网所创建的.它需要巨量的工作, ...
- PHP随机产生10个100以内互不相同的正整数按从小到大的顺序输出
<?php //产生1~100的正整数 $numbers = range(1,100); //从1~100中选出10个不重复的整数,并使用函数进行排序 $randNumbers = array_ ...
- NFS pv部署
一.部署nfs服务端: 可以选择kubernetes_cluster内的任意的node去做为nfs服务端,部署节点也可以.我选择的是部署节点去做为nfs服务端. (1)部署节点安装nfs服务软件包: ...
- [HDU 3521] [最小割] Being a Hero
题意: 在一个有向图中,有n个点,m条边$n \le 1000 \And \And m \le 100000$ 每条边有一个破坏的花费,有些点可以被选择并获得对应的金币. 假设一个可以选的点是$x$ ...
- java8学习之groupingByConcurrent与partioningBy源码分析
在上一次[http://www.cnblogs.com/webor2006/p/8387656.html]中对于Collectors.groupingBy()方法进行了完整的分析之后,接着继续来分析一 ...
- mongodb 3.0 WT 引擎性能测试(转载)
网上转载来的测试,仅供参考.原文地址:http://www.mongoing.com/benchmark_3_0 类机器. 测试均在单机器,单实例的情况下进行. 机器A(cache 12G,即内存&g ...
- 零拷贝的原理及Java实现
在谈论Kafka高性能时不得不提到零拷贝.Kafka通过采用零拷贝大大提供了应用性能,减少了内核和用户模式之间的上下文切换次数.那么什么是零拷贝,如何实现零拷贝呢? 什么是零拷贝 WIKI中对其有如下 ...
- 微信里关闭窗口 js
需要在微信中关闭页面窗口,不过window.close()不管用,问过群里才知道微信有自带的方法能关闭窗口,记录一下(这个只针对微信有效哦): WeixinJSBridge.call('closeWi ...
- 【leetcode】1260. Shift 2D Grid
题目如下: Given a 2D grid of size n * m and an integer k. You need to shift the grid k times. In one shi ...
- LAMP 搭建,wordpress.xcache,powerdns及poweradmin
一,概念 CGI: CGI全称是通用网关接口(Common Gateway Interface),是外部应用程序与与服务器之间的接口标准,是在CGI程序和web服务器之间传递信息的规程 CGI是一段程 ...