Android 实现伸缩布局效果示例代码

最近项目实现下面的图示的效果,本来想用listview+gridview实现,但是貌似挺麻烦的于是就用flowlayout 来addview实现添加伸缩的效果,实现也比较简单。

mainActivity 布局

<?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="match_parent" android:orientation="vertical" > <RelativeLayout android:id="@+id/rl_category_title_bar_layout" android:layout_height="wrap_content" android:layout_width="match_parent" > <RelativeLayout android:layout_height="50dp" android:layout_width="match_parent" > <TextView android:id="@+id/tv_category_title" android:layout_height="50dp" android:layout_width="wrap_content" android:text="分类" android:textSize="18sp" android:layout_centerInParent="true" android:gravity="center" /> </RelativeLayout> </RelativeLayout> <ListView android:id="@+id/lv_category_menu" android:layout_height="match_parent" android:layout_width="match_parent" /> </LinearLayout>

自定义布局flowlayout

package comskyball.addflowlayout; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import java.util.ArrayList; import java.util.List; public class FlowLayout extends ViewGroup { private Context mContext; private int usefulWidth; // the space of a line we can use(line's width minus the sum of left and right padding private int lineSpacing = 0; // the spacing between lines in flowlayout List<View> childList = new ArrayList(); List<Integer> lineNumList = new ArrayList(); public FlowLayout(Context context) { this(context, null); } public FlowLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mContext = context; TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.FlowLayout); lineSpacing = mTypedArray.getDimensionPixelSize( R.styleable.FlowLayout_lineSpacing, 0); mTypedArray.recycle(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int mPaddingLeft = getPaddingLeft(); int mPaddingRight = getPaddingRight(); int mPaddingTop = getPaddingTop(); int mPaddingBottom = getPaddingBottom(); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int lineUsed = mPaddingLeft + mPaddingRight; int lineY = mPaddingTop; int lineHeight = 0; for (int i = 0; i < this.getChildCount(); i++) { View child = this.getChildAt(i); if (child.getVisibility() == GONE) { continue; } int spaceWidth = 0; int spaceHeight = 0; LayoutParams childLp = child.getLayoutParams(); if (childLp instanceof MarginLayoutParams) { measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, lineY); MarginLayoutParams mlp = (MarginLayoutParams) childLp; spaceWidth = mlp.leftMargin + mlp.rightMargin; spaceHeight = mlp.topMargin + mlp.bottomMargin; } else { measureChild(child, widthMeasureSpec, heightMeasureSpec); } int childWidth = child.getMeasuredWidth(); int childHeight = child.getMeasuredHeight(); spaceWidth += childWidth; spaceHeight += childHeight; if (lineUsed + spaceWidth > widthSize) { //approach the limit of width and move to next line lineY += lineHeight + lineSpacing; lineUsed = mPaddingLeft + mPaddingRight; lineHeight = 0; } if (spaceHeight > lineHeight) { lineHeight = spaceHeight; } lineUsed += spaceWidth; } setMeasuredDimension( widthSize, heightMode == MeasureSpec.EXACTLY ? heightSize : lineY + lineHeight + mPaddingBottom ); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int mPaddingLeft = getPaddingLeft(); int mPaddingRight = getPaddingRight(); int mPaddingTop = getPaddingTop(); int lineX = mPaddingLeft; int lineY = mPaddingTop; int lineWidth = r - l; usefulWidth = lineWidth - mPaddingLeft - mPaddingRight; int lineUsed = mPaddingLeft + mPaddingRight; int lineHeight = 0; int lineNum = 0; lineNumList.clear(); for (int i = 0; i < this.getChildCount(); i++) { View child = this.getChildAt(i); if (child.getVisibility() == GONE) { continue; } int spaceWidth = 0; int spaceHeight = 0; int left = 0; int top = 0; int right = 0; int bottom = 0; int childWidth = child.getMeasuredWidth(); int childHeight = child.getMeasuredHeight(); LayoutParams childLp = child.getLayoutParams(); if (childLp instanceof MarginLayoutParams) { MarginLayoutParams mlp = (MarginLayoutParams) childLp; spaceWidth = mlp.leftMargin + mlp.rightMargin; spaceHeight = mlp.topMargin + mlp.bottomMargin; left = lineX + mlp.leftMargin; top = lineY + mlp.topMargin; right = lineX + mlp.leftMargin + childWidth; bottom = lineY + mlp.topMargin + childHeight; } else { left = lineX; top = lineY; right = lineX + childWidth; bottom = lineY + childHeight; } spaceWidth += childWidth; spaceHeight += childHeight; if (lineUsed + spaceWidth > lineWidth) { //approach the limit of width and move to next line lineNumList.add(lineNum); lineY += lineHeight + lineSpacing; lineUsed = mPaddingLeft + mPaddingRight; lineX = mPaddingLeft; lineHeight = 0; lineNum = 0; if (childLp instanceof MarginLayoutParams) { MarginLayoutParams mlp = (MarginLayoutParams) childLp; left = lineX + mlp.leftMargin; top = lineY + mlp.topMargin; right = lineX + mlp.leftMargin + childWidth; bottom = lineY + mlp.topMargin + childHeight; } else { left = lineX; top = lineY; right = lineX + childWidth; bottom = lineY + childHeight; } } child.layout(left, top, right, bottom); lineNum ++; if (spaceHeight > lineHeight) { lineHeight = spaceHeight; } lineUsed += spaceWidth; lineX += spaceWidth; } // add the num of last line lineNumList.add(lineNum); } /** * resort child elements to use lines as few as possible */ public void relayoutToCompress() { int childCount = this.getChildCount(); if (0 == childCount) { //no need to sort if flowlayout has no child view return; } int count = 0; for (int i = 0; i < childCount; i++) { View v = getChildAt(i); if (v instanceof BlankView) { //BlankView is just to make childs look in alignment, we should ignore them when we relayout continue; } count++; } View[] childs = new View[count]; int[] spaces = new int[count]; int n = 0; for (int i = 0; i < childCount; i++) { View v = getChildAt(i); if (v instanceof BlankView) { //BlankView is just to make childs look in alignment, we should ignore them when we relayout continue; } childs[n] = v; LayoutParams childLp = v.getLayoutParams(); int childWidth = v.getMeasuredWidth(); if (childLp instanceof MarginLayoutParams) { MarginLayoutParams mlp = (MarginLayoutParams) childLp ; spaces[n] = mlp.leftMargin + childWidth + mlp.rightMargin; } else { spaces[n] = childWidth; } n++; } int[] compressSpaces = new int[count]; for (int i = 0; i < count; i++) { compressSpaces[i] = spaces[i] > usefulWidth ? usefulWidth : spaces[i]; } sortToCompress(childs, compressSpaces); this.removeAllViews(); for (View v : childList) { this.addView(v); } childList.clear(); } private void sortToCompress(View[] childs, int[] spaces) { int childCount = childs.length; int[][] table = new int[childCount + 1][usefulWidth + 1]; for (int i = 0; i < childCount +1; i++) { for (int j = 0; j < usefulWidth; j++) { table[i][j] = 0; } } boolean[] flag = new boolean[childCount]; for (int i = 0; i < childCount; i++) { flag[i] = false; } for (int i = 1; i <= childCount; i++) { for (int j = spaces[i-1]; j <= usefulWidth; j++) { table[i][j] = (table[i-1][j] > table[i-1][j-spaces[i-1]] + spaces[i-1]) ? table[i-1][j] : table[i-1][j-spaces[i-1]] + spaces[i-1]; } } int v = usefulWidth; for (int i = childCount ; i > 0 && v >= spaces[i-1]; i--) { if (table[i][v] == table[i-1][v-spaces[i-1]] + spaces[i-1]) { flag[i-1] = true; v = v - spaces[i - 1]; } } int rest = childCount; View[] restArray; int[] restSpaces; for (int i = 0; i < flag.length; i++) { if (flag[i] == true) { childList.add(childs[i]); rest--; } } if (0 == rest) { return; } restArray = new View[rest]; restSpaces = new int[rest]; int index = 0; for (int i = 0; i < flag.length; i++) { if (flag[i] == false) { restArray[index] = childs[i]; restSpaces[index] = spaces[i]; index++; } } table = null; childs = null; flag = null; sortToCompress(restArray, restSpaces); } /** * add some blank view to make child elements look in alignment */ public void relayoutToAlign() { int childCount = this.getChildCount(); if (0 == childCount) { //no need to sort if flowlayout has no child view return; } int count = 0; for (int i = 0; i < childCount; i++) { View v = getChildAt(i); if (v instanceof BlankView) { //BlankView is just to make childs look in alignment, we should ignore them when we relayout continue; } count++; } View[] childs = new View[count]; int[] spaces = new int[count]; int n = 0; for (int i = 0; i < childCount; i++) { View v = getChildAt(i); if (v instanceof BlankView) { //BlankView is just to make childs look in alignment, we should ignore them when we relayout continue; } childs[n] = v; LayoutParams childLp = v.getLayoutParams(); int childWidth = v.getMeasuredWidth(); if (childLp instanceof MarginLayoutParams) { MarginLayoutParams mlp = (MarginLayoutParams) childLp ; spaces[n] = mlp.leftMargin + childWidth + mlp.rightMargin; } else { spaces[n] = childWidth; } n++; } int lineTotal = 0; int start = 0; this.removeAllViews(); for (int i = 0; i < count; i++) { if (lineTotal + spaces[i] > usefulWidth) { int blankWidth = usefulWidth - lineTotal; int end = i - 1; int blankCount = end - start; if (blankCount >= 0) { if (blankCount > 0) { int eachBlankWidth = blankWidth / blankCount; MarginLayoutParams lp = new MarginLayoutParams(eachBlankWidth, 0); for (int j = start; j < end; j++) { this.addView(childs[j]); BlankView blank = new BlankView(mContext); this.addView(blank, lp); } } this.addView(childs[end]); start = i; i --; lineTotal = 0; } else { this.addView(childs[i]); start = i + 1; lineTotal = 0; } } else { lineTotal += spaces[i]; } } for (int i = start; i < count; i++) { this.addView(childs[i]); } } /** * use both of relayout methods together */ public void relayoutToCompressAndAlign(){ this.relayoutToCompress(); this.relayoutToAlign(); } /** * cut the flowlayout to the specified num of lines * @param line_num */ public void specifyLines(int line_num) { int childNum = 0; if (line_num > lineNumList.size()) { line_num = lineNumList.size(); } for (int i = 0; i < line_num; i++) { childNum += lineNumList.get(i); } List<View> viewList = new ArrayList<View>(); for (int i = 0; i < childNum; i++) { viewList.add(getChildAt(i)); } removeAllViews(); for (View v : viewList) { addView(v); } } @Override protected LayoutParams generateLayoutParams(LayoutParams p) { return new MarginLayoutParams(p); } @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new MarginLayoutParams(getContext(), attrs); } @Override protected LayoutParams generateDefaultLayoutParams() { return new MarginLayoutParams(super.generateDefaultLayoutParams()); } class BlankView extends View { public BlankView(Context context) { super(context); } } }

adapter

package comskyball.addflowlayout; import java.util.ArrayList; import android.content.Context; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; public class CategoryLvAdapter extends BaseAdapter { public Context context; public ArrayList<Category> list; public boolean isMore=true; public CategoryLvAdapter(Context context,ArrayList<Category> list) { this.context=context; this.list=list; } @Override public int getCount() { return list.size(); } @Override public Object getItem(int position) { return 0; } @Override public long getItemId(int position) { return 0; } @Override public View getView(final int position, View convertView, ViewGroup parent) { ViewHolder viewHolder=null; if(convertView==null){ convertView=View.inflate(context, R.layout.lv_category_item, null); viewHolder=new ViewHolder(); viewHolder.iv_lv_category_img=(ImageView) convertView.findViewById(R.id.iv_lv_category_img); viewHolder.tv_lv_category=(TextView) convertView.findViewById(R.id.tv_lv_category); viewHolder.flow_layout_lv_category=(FlowLayout) convertView.findViewById(R.id.flow_layout_lv_category); viewHolder.ll_lv_category_add=(LinearLayout) convertView.findViewById(R.id.ll_lv_category_add); viewHolder.iv_lv_category_arrow=(ImageView) convertView.findViewById(R.id.iv_lv_category_arrow); convertView.setTag(viewHolder); }else{ viewHolder=(ViewHolder) convertView.getTag(); } // ImageLoader.getInstance().displayImage(AppConfig.APP_URL+list.get(position).getImg(),viewHolder.iv_lv_category_img,App.normalOption); viewHolder.tv_lv_category.setText(list.get(position).getCate_name()); viewHolder.iv_lv_category_arrow.setBackgroundResource(R.drawable.arrow_down); viewHolder.flow_layout_lv_category.removeAllViews(); Utils.addflow(context,6, list.get(position).getNext(),viewHolder.flow_layout_lv_category); final FlowLayout flowLayoutLvCategory = viewHolder.flow_layout_lv_category; final ImageView ivLvCategoryArrow = viewHolder.iv_lv_category_arrow; viewHolder.ll_lv_category_add.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if(isMore){ isMore=false; flowLayoutLvCategory.removeAllViews(); Utils.addflow(context,list.get(position).getNext().size(), list.get(position).getNext(),flowLayoutLvCategory); ivLvCategoryArrow.setBackgroundResource(R.drawable.arrow_up); }else{ isMore=true; flowLayoutLvCategory.removeAllViews(); Utils.addflow(context,6, list.get(position).getNext(),flowLayoutLvCategory); ivLvCategoryArrow.setBackgroundResource(R.drawable.arrow_down); } } }); return convertView; } public class ViewHolder{ public ImageView iv_lv_category_img; public TextView tv_lv_category; public FlowLayout flow_layout_lv_category; public LinearLayout ll_lv_category_add; public ImageView iv_lv_category_arrow; } }

adapter item布局

<?xml version="1.0" encoding="utf-8"?> <RelativeLayout 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" > <LinearLayout android:layout_height="wrap_content" android:layout_width="match_parent" android:orientation="vertical" > <RelativeLayout android:layout_height="35dp" android:layout_width="match_parent" > <ImageView android:id="@+id/iv_lv_category_img" style="@style/category_iv_left_style" /> <TextView android:id="@+id/tv_lv_category" style="@style/category_tv_style" android:text="衣食" android:layout_toRightOf="@id/iv_lv_category_img" /> </RelativeLayout> <View style="@style/category_view_style" /> <ScrollView android:layout_width="match_parent" android:layout_height="match_parent" > <RelativeLayout android:layout_height="match_parent" android:layout_width="match_parent" > <comskyball.addflowlayout.FlowLayout android:id="@+id/flow_layout_lv_category" android:layout_width="match_parent" android:layout_height="wrap_content" app:lineSpacing="10dp" app:maxLine="3" android:background="#F0F0F0" android:layout_marginTop="5dp" /> <LinearLayout android:id="@+id/ll_lv_category_add" style="@style/category_ll_style" android:layout_height="35dp" android:layout_below="@id/flow_layout_lv_category" > <ImageView android:id="@+id/iv_lv_category_arrow" style="@style/category_iv_style" android:background="@drawable/arrow_down" /> <View style="@style/category_view_style" /> </LinearLayout> </RelativeLayout> </ScrollView> </LinearLayout> </RelativeLayout>

以上所述是小编给大家介绍的Android 实现伸缩布局效果,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

时间: 2024-08-02 05:37:29

Android 实现伸缩布局效果示例代码的相关文章

Android DrawerLayout实现抽屉效果实例代码

官网:https://developer.android.com/training/implementing-navigation/nav-drawer.html 贴上主要的逻辑和布局文件: activity_main.xml <?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.DrawerLayout xmlns:android="http://schema

android界面布局之实现文本块布局效果示例_Android

复制代码 代码如下: package cn.aibow.android.layoutdemo1; import android.os.Bundle;import android.app.Activity;import android.view.Menu;import android.view.MotionEvent;import android.view.View;import android.widget.TextView;import android.widget.Toast; public

android界面布局之实现文本块布局效果示例

复制代码 代码如下:package cn.aibow.android.layoutdemo1; import android.os.Bundle;import android.app.Activity;import android.view.Menu;import android.view.MotionEvent;import android.view.View;import android.widget.TextView;import android.widget.Toast; public

Android Menu详解及示例代码_Android

Android Menu 详细介绍: 1.选项菜单 OptionsMenu 2.上下文菜单 ContextMenu 3.子菜单 SubMenu 组成Android用户界面的除了View以外,还有菜单和对话框,这一讲我们就共同学习一下菜单的使用. 菜单是用户界面中最常见的元素,使用也非常频繁,在Android中,菜单被分为如下三种,选项菜单(OptionsMenu).上下文菜单(ContextMenu)和子菜单(SubMenu),下面分别举例说明. 一.选项菜单 OptionsMenu Andro

Android刮刮卡效果实现代码_Android

本文实例为大家分享了Android刮刮卡效果,供大家参考,具体内容如下 android实现底层一张图片,上层一个遮罩层,触摸滑动按手指滑动路径实现去除遮罩效果,类似于抽奖的刮刮卡一样,不多说先上张效果图: 直接上代码: XfermodeView.java  /** * Created by 57 on 2016-4-21. */ public class XfermodeView extends View{ private Bitmap mBgBitmap,mFgBitmap; private

Android GPS详解及示例代码_Android

LBS(Location Based Services)直译的话就是基于地理位置的服务,这里面至少有两层意思,第一要能轻易的获取当前的地理位置,譬如经纬度海拔等,另一个就是在当前位置的基础上提供增值服务,譬如找附近的加油站.餐馆.酒店等.这里面的第一步:获取用户当前位置,我们就可以用Android的GPS定位服务来得到.Android提供了基于网络的定位服务和基于卫星的定位服务两种.在设置->位置和安全设置里面的前三项就是,最后一个增强型GPS是为了辅助快速找卫星的.  那么我们现在就写一个简单

Android Service详解及示例代码_Android

Android Service 详细介绍: 1.Service的概念 2.Service的生命周期 3.实例:控制音乐播放的Service 一.Service的概念 Service是Android程序中四大基础组件之一,它和Activity一样都是Context的子类,只不过它没有UI界面,是在后台运行的组件. 二.Service的生命周期 Service对象不能自己启动,需要通过某个Activity.Service或者其他Context对象来启动.启动的方法有两种,Context.startS

Android SQLite详解及示例代码_Android

在Android中使用SQLite数据库的入门指南,打算分下面几部分与大家一起分享, 1.什么是SQLite 2.Android中使用SQLite 一.什么是SQLite SQLite是一款开源的.轻量级的.嵌入式的.关系型数据库.它在2000年由D. Richard Hipp发布,可以支援Java.Net.PHP.Ruby.Python.Perl.C等几乎所有的现代编程语言,支持Windows.Linux.Unix.Mac OS.Android.IOS等几乎所有的主流操作系统平台. SQLit

Android GridView实现动画效果实现代码

Android GridView实现动画效果 项目中用到的一些动画,GridView的Item依次从屏幕外飞入到相应位置,附上相关代码: MainActivity.Java package com.mundane.gridanimationdemo; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.view.ani