日本搞逼视频_黄色一级片免费在线观看_色99久久_性明星video另类hd_欧美77_综合在线视频

國內(nèi)最全I(xiàn)T社區(qū)平臺(tái) 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁 > php開源 > 綜合技術(shù) > 自定義View常用例子二(點(diǎn)擊展開隱藏控件,九宮格圖片控件)

自定義View常用例子二(點(diǎn)擊展開隱藏控件,九宮格圖片控件)

來源:程序員人生   發(fā)布時(shí)間:2016-07-04 16:42:41 閱讀次數(shù):3071次

自定義View經(jīng)常使用例子2(點(diǎn)擊展開隱藏控件,9宮格圖片控件)

今天博客的主要內(nèi)容是兩個(gè)常見的自定義控件,第1個(gè)是我們常常看到的點(diǎn)擊隱藏點(diǎn)擊查看控件,第2個(gè)控件是仿微信朋友圈的9宮格圖片控件,相對(duì)上1篇的流布式布局來講,這篇博客更容易,只不過觸及更多的知識(shí)點(diǎn)而已

轉(zhuǎn)載請(qǐng)注明原博客地址:http://blog.csdn.net/gdutxiaoxu/article/details/51772308

1.空話不多說了,先來看1下效果圖

  1. 圖1效果,點(diǎn)擊隱藏,展開


  1. 圖2效果,類似于朋友圈9宮格圖片


圖2源碼下載地址

圖1源碼下載地址:

圖1源碼

```

public class CollapseView extends LinearLayout { private long duration = 350; private Context mContext; private TextView mNumberTextView; private TextView mTitleTextView; private RelativeLayout mContentRelativeLayout; private RelativeLayout mTitleRelativeLayout; private ImageView mArrowImageView; int parentWidthMeasureSpec; int parentHeightMeasureSpec; private String TAG = "xujun"; public CollapseView(Context context) { this(context, null); } public CollapseView(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; LayoutInflater.from(mContext).inflate(R.layout.collapse_layout, this); initView(); } private void initView() { mNumberTextView = (TextView) findViewById(R.id.numberTextView); mTitleTextView = (TextView) findViewById(R.id.titleTextView); mTitleRelativeLayout = (RelativeLayout) findViewById(R.id.titleRelativeLayout); mContentRelativeLayout = (RelativeLayout) findViewById(R.id.contentRelativeLayout); mArrowImageView = (ImageView) findViewById(R.id.arrowImageView); mTitleRelativeLayout.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { rotateArrow(); } }); mNumberTextView.setBackgroundResource(R.drawable.circle); Drawable circleShape = createCircleShape(Color.BLACK); mNumberTextView.setBackgroundDrawable(circleShape); collapse(mContentRelativeLayout); } public void setNumber(String number) { if (!TextUtils.isEmpty(number)) { mNumberTextView.setText(number); } } public void setTitle(String title) { if (!TextUtils.isEmpty(title)) { mTitleTextView.setText(title); } } public void setContent(int resID) { View view = LayoutInflater.from(mContext).inflate(resID, null); RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, RelativeLayout .LayoutParams.WRAP_CONTENT); view.setLayoutParams(layoutParams); mContentRelativeLayout.addView(view); } /** * 若使用這個(gè)方法,強(qiáng)迫layoutParams must be RelativeLayout.LayoutParams,避免在某些情況下出現(xiàn)毛病 * * @param view */ public void setContent(View view) { ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); if (layoutParams == null) { layoutParams = new RelativeLayout.LayoutParams( LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT); } if (!(layoutParams instanceof RelativeLayout.LayoutParams)) { throw new IllegalStateException("layoutParams must be RelativeLayout.LayoutParams "); } view.setLayoutParams(layoutParams); mContentRelativeLayout.addView(view); } public void rotateArrow() { int degree = 0; if (mArrowImageView.getTag() == null || mArrowImageView.getTag().equals(true)) { mArrowImageView.setTag(false); degree = ⑴80; expand(mContentRelativeLayout); } else { degree = 0; mArrowImageView.setTag(true); collapse(mContentRelativeLayout); } mArrowImageView.animate().setDuration(duration).rotation(degree); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); parentWidthMeasureSpec = widthMeasureSpec; parentHeightMeasureSpec = heightMeasureSpec; } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); } // 展開 private void expand(final View view) { view.setVisibility(View.VISIBLE); int childWidthMode = getMode(parentWidthMeasureSpec); int childHeightMode = getMode(parentHeightMeasureSpec); view.measure(childWidthMode, childHeightMode); final int measuredWidth = view.getMeasuredWidth(); final int measuredHeight = view.getMeasuredHeight(); final ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1); valueAnimator.setDuration(duration); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float precent = animation.getAnimatedFraction(); int width = (int) (measuredWidth * precent); setWidth(view, width); if (precent == 1) { valueAnimator.removeAllUpdateListeners(); } } }); valueAnimator.start(); } private int getMode(int parentMeasureSpec) { if (parentMeasureSpec == MeasureSpec.EXACTLY) { return MeasureSpec.AT_MOST; } else if (parentMeasureSpec == MeasureSpec.AT_MOST) { return MeasureSpec.AT_MOST; } else { return parentMeasureSpec; } } private void setWidth(View view, int width) { ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); layoutParams.width = width; view.setLayoutParams(layoutParams); view.requestLayout(); } // 折疊 private void collapse(final View view) { final int measuredHeight = view.getMeasuredHeight(); final ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1); valueAnimator.setDuration(duration); final int viewMeasuredWidth = view.getMeasuredWidth(); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float precent = animation.getAnimatedFraction(); Log.i(TAG, "onAnimationUpdate: precent" + precent); int width = (int) (viewMeasuredWidth - viewMeasuredWidth * precent); setWidth(view, width); // 動(dòng)畫履行結(jié)束的時(shí)候,設(shè)置View為View.GONE,同時(shí)移除監(jiān)聽器 if (precent == 1) { view.setVisibility(View.GONE); valueAnimator.removeAllUpdateListeners(); } } }); valueAnimator.start(); } }

```

思路解析

  1. 如圖所示,圖逐一4個(gè)部份組成,數(shù)字,標(biāo)題,箭頭,圖片,點(diǎn)擊標(biāo)題所在的那1行,圖片回相應(yīng)地隱藏或顯示。
  2. 數(shù)字,標(biāo)題,箭頭都在同1個(gè)相對(duì)布局里面,圖片在單獨(dú)的1個(gè)相對(duì)布局中,整體由 LinearLayout構(gòu)成,布局文件以下

```

<?xml version="1.0" encoding="utf⑻"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#ffffff" android:orientation="vertical"> <RelativeLayout android:id="@+id/titleRelativeLayout" android:padding="30px" android:layout_width="match_parent" android:layout_height="170px" android:clickable="true"> <TextView android:id="@+id/numberTextView" android:layout_width="70px" android:layout_height="70px" android:gravity="center" android:layout_centerVertical="true" android:clickable="false" android:text="1" android:textStyle="bold" android:textColor="#EBEFEC" android:textSize="35px" /> <TextView android:id="@+id/titleTextView" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_toRightOf="@id/numberTextView" android:layout_marginLeft="30px" android:clickable="false" android:textColor="#1d953f" android:textSize="46px" /> <ImageView android:id="@+id/arrowImageView" android:layout_width="48px" android:layout_height="27px" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:background="@mipmap/arrow_down" android:clickable="false" android:scaleType="fitCenter" /> </RelativeLayout> <View android:layout_width="match_parent" android:layout_height="2px" android:layout_below="@id/titleRelativeLayout" android:background="#E7E7EF" android:clickable="false" /> <RelativeLayout android:id="@+id/contentRelativeLayout" android:visibility="gone" android:layout_width="match_parent" android:layout_height="wrap_content"> </RelativeLayout> </LinearLayout>

```

把contentRelativeLayout的visibility設(shè)置為android:visibility="gone",是由于1開始不用加載這個(gè)相對(duì)局部,這樣它不會(huì)占用位置

3. 在代碼中初始化布局,并給 mTitleRelativeLayout設(shè)置點(diǎn)擊事件。


mTitleRelativeLayout.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { rotateArrow(); } });

我們來看 rotateArrow()里面我們做了甚么,其實(shí)就是根據(jù)相應(yīng)的動(dòng)畫履行箭頭旋轉(zhuǎn)的動(dòng)作和更改 contentRelativeLayout的高度 核心代碼以下:


int degree = 0; if (mArrowImageView.getTag() == null || mArrowImageView.getTag().equals(true)) { mArrowImageView.setTag(false); degree = ⑴80; expand(mContentRelativeLayout); } else { degree = 0; mArrowImageView.setTag(true); collapse(mContentRelativeLayout); } mArrowImageView.animate().setDuration(duration).rotation(degree);

我們?cè)趤砜?下在expand我們做了甚么,其實(shí)就是給contentRelativeLayout履行1個(gè)動(dòng)畫,在動(dòng)畫的履行進(jìn)程中不斷改變contentRelativeLayout的高度,注意在履行動(dòng)畫之前,我們需要小調(diào)用view.measure(childWidthMode, childHeightMode);方法,這樣我們可能獲得到高度


view.setVisibility(View.VISIBLE); int childWidthMode = getMode(parentWidthMeasureSpec); int childHeightMode = getMode(parentHeightMeasureSpec); view.measure(childWidthMode, childHeightMode); final int measuredWidth = view.getMeasuredWidth(); final int measuredHeight = view.getMeasuredHeight(); final ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1); valueAnimator.setDuration(duration); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float precent = animation.getAnimatedFraction(); int width = (int) (measuredWidth * precent); setWidth(view, width); // 動(dòng)畫履行結(jié)束的時(shí)候,同時(shí)移除監(jiān)聽器 if (precent == 1) { valueAnimator.removeAllUpdateListeners(); } } }); valueAnimator.start();

反之,隱藏也是履行1個(gè)動(dòng)畫,不斷改變高度,只不太高度 是愈來愈小,直至為0為止

圖1的源碼分析到此為止,源碼下載地址:https://github.com/gdutxiaoxu/CustomViewDemo2.git


圖2源碼分析

源碼下載地址

1.思路解析,

1)首先我們自己自定義1個(gè)CustomImageView,在這個(gè)類里面我們給其提供了1個(gè)方法

public void setImageUrl(String url);

在這個(gè)方法里面其實(shí)我們做的工作就是Picasso框架加載圖片,即圖片交給CustomImageView自己去加載,更符合面向?qū)ο蟮?位

if (!TextUtils.isEmpty(url)) { this.url = url; if (isAttachedToWindow) { Picasso.with(getContext()).load(url).placeholder(new ColorDrawable(Color.parseColor("#f5f5f5"))).into(this); } }

2)接著我們自定義1個(gè)NineGridlayout,繼承ViewGroup,在這個(gè)類里面我們主要做的工作就是添加孩子,并肯定每一個(gè)孩子的位置

首先我們?cè)跇?gòu)造方法里面初始化我們控件需要的寬度

public NineGridlayout(Context context, AttributeSet attrs) { super(context, attrs); ScreenTools screenTools=ScreenTools.instance(getContext()); // 初始總寬度 totalWidth=screenTools.getScreenWidth()-screenTools.dip2px(80); }

接著我們提供了setImagesData()方法,基本所有的邏輯都放在這里

  • 首先我們先根據(jù)孩子的數(shù)量肯定有多少行多少列
  • 接著判斷是不是需要復(fù)用 ,不需要復(fù)用的話,直接添加孩子,需要復(fù)用的話,判斷需要新設(shè)置的孩子的數(shù)量是不是大于緩存的孩子的數(shù)量,小于的話,繼續(xù)添加孩子,知道孩子的數(shù)量到達(dá)我們需要的孩子的數(shù)量為止,小于的話,移除過剩的緩存的孩子的數(shù)量
  • 接著再擺放每一個(gè)孩子的位置,并設(shè)置它的Url

注意我們這里之所以需要判斷是不是需要復(fù)用,是由于ListView或RecyclerView的緩存機(jī)制,若每次setImagesData()的時(shí)候直接添加,會(huì)致使添加多個(gè)孩子,若直接移除所有孩子的話,性能相對(duì)來講較差,所以我們進(jìn)行緩存,到此源碼分析位置。

代碼以下

/** * 博客地址:http://blog.csdn.net/gdutxiaoxu * @author xujun * @time 2015/11/27 16:13. */ public class NineGridlayout extends ViewGroup { /** * 圖片之間的間隔 */ private int gap = 5; private int columns;//列數(shù) private int rows;//行數(shù) private List listData; private int totalWidth; private final int MAX_COLUMNS=3; private final int MAX_ROW3=3; public NineGridlayout(Context context) { this(context,null); } public NineGridlayout(Context context, AttributeSet attrs) { super(context, attrs); ScreenTools screenTools=ScreenTools.instance(getContext()); // 初始總寬度 totalWidth=screenTools.getScreenWidth()-screenTools.dip2px(80); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { } private void layoutChildrenView(){ int childrenCount = listData.size(); int singleWidth = (totalWidth - gap * (3 - 1)) / 3; int singleHeight = singleWidth; /** * 根據(jù)子view數(shù)量肯定高度,這里直接調(diào)用setLayoutParams設(shè)置NineGridlayout的高度 * */ LayoutParams params = getLayoutParams(); int marginHeight = getPaddingTop() + getPaddingTop(); params.height = singleHeight * rows + gap * (rows - 1)+marginHeight; setLayoutParams(params); //擺放孩子的位置 for (int i = 0; i < childrenCount; i++) { CustomImageView childrenView = (CustomImageView) getChildAt(i); childrenView.setImageUrl(((Image) listData.get(i)).getUrl()); int[] position = findPosition(i); // 加上getPaddingLeft(),為了支持Padding屬性 int left = (singleWidth + gap) * position[1]+getPaddingLeft(); int top = (singleHeight + gap) * position[0]+getPaddingTop(); int right = left + singleWidth; int bottom = top + singleHeight; childrenView.layout(left, top, right, bottom); } } private int[] findPosition(int childNum) { int[] position = new int[2]; for (int i = 0; i < rows; i++) { for (int j = 0; j < columns; j++) { if ((i * columns + j) == childNum) { position[0] = i;//行 position[1] = j;//列 break; } } } return position; } public int getGap() { return gap; } public void setGap(int gap) { this.gap = gap; } public void setImagesData(List<Image> lists) { if (lists == null || lists.isEmpty()) { return; } //初始化布局 generateChildrenLayout(lists.size()); //這里做1個(gè)重用view的處理 if (listData == null) { int i = 0; while (i < lists.size()) { CustomImageView iv = generateImageView(); addView(iv,generateDefaultLayoutParams()); i++; } } else { int oldViewCount = listData.size(); int newViewCount = lists.size(); if (oldViewCount > newViewCount) { removeViews(newViewCount - 1, oldViewCount - newViewCount); } else if (oldViewCount < newViewCount) { for (int i = 0; i < newViewCount - oldViewCount; i++) { CustomImageView iv = generateImageView(); addView(iv,generateDefaultLayoutParams()); } } } listData = lists; layoutChildrenView(); } /** * 根據(jù)圖片個(gè)數(shù)肯定行列數(shù)量 * 對(duì)應(yīng)關(guān)系以下 * num row column * 1 1 1 * 2 1 2 * 3 1 3 * 4 2 2 * 5 2 3 * 6 2 3 * 7 3 3 * 8 3 3 * 9 3 3 * * @param length */ private void generateChildrenLayout(int length) { if (length <= MAX_COLUMNS) { rows = 1; columns = length; } else if (length <= MAX_COLUMNS*2) { rows = 2; columns = MAX_COLUMNS; if (length == MAX_COLUMNS+1) { columns = 2; } } else { rows = 3; columns = MAX_COLUMNS; } } private CustomImageView generateImageView() { CustomImageView iv = new CustomImageView(getContext()); iv.setScaleType(ImageView.ScaleType.CENTER_CROP); iv.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { } }); iv.setBackgroundColor(Color.parseColor("#f5f5f5")); return iv; } }

圖2源碼下載地址

圖1源碼下載地址:

生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對(duì)您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈(zèng)
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 97av在线视频免费播放 | 天天操夜夜曰 | 成人免费视频网站 | 久久综合一区二区 | 99久久国产综合精品女不卡 | 日韩男人天堂 | 99久久99久久精品国产片果冻 | 天堂√最新版中文在线 | 中文字幕av亚洲精品一部二部 | 大桥未久中文字幕 | 精品国产一 | 一区二区国产在线观看 | 欧美精品在线观看 | 一级二级在线观看 | 91福利视频合集 | 亚洲欧洲一区二区 | 国内视频一区 | 91理论电影| 婷婷成人影院 | 亚洲一区精品视频 | a天堂视频 | 国产视频不卡 | 国产精品一区二区电影 | 欧美一级电影 | 日韩一区二区三区视频在线观看 | 欧美中文字幕在线 | 国产精品日韩欧美一区二区 | 国产精品29页 | 嫩草影视大全 | 国产精品久久久久久久第一福利 | 国产日韩欧美在线观看 | 免费黄色在线看 | 精品一区二区三区在线视频 | 秋霞偷拍 | 麻豆传媒免费观看 | 国产一区二区三区在线 | 日韩国产精品一区二区 | 国产精品伦一区二区三级视频 | 国产精品亚洲综合 | 久久诱惑 | 91精品久久久久久久99蜜桃 |