Repository: bingoogolapple/BGAFlowLayout-Android
Branch: master
Commit: c371484b5f50
Files: 25
Total size: 31.8 KB
Directory structure:
gitextract_0knqr_xt/
├── .gitignore
├── README.md
├── build.gradle
├── demo/
│ ├── build.gradle
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ ├── java/
│ │ └── cn/
│ │ └── bingoogolapple/
│ │ └── flowlayout/
│ │ └── demo/
│ │ └── MainActivity.java
│ └── res/
│ ├── drawable/
│ │ ├── selector_tag.xml
│ │ └── shape_stroke_line.xml
│ ├── layout/
│ │ └── activity_main.xml
│ ├── values/
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ ├── styles.xml
│ │ └── styles_base.xml
│ └── values-v21/
│ └── styles.xml
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── library/
│ ├── build.gradle
│ ├── gradle.properties
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ ├── java/
│ │ └── cn/
│ │ └── bingoogolapple/
│ │ └── flowlayout/
│ │ └── BGAFlowLayout.java
│ └── res/
│ └── values/
│ └── attrs.xml
└── settings.gradle
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# Built application files
*.apk
*.ap_
# Files for the Dalvik VM
*.dex
# Java class files
*.class
# Generated files
bin/
gen/
# Gradle files
.gradle/
build/
/*/build/
# Local configuration file (sdk path, etc)
local.properties
# Proguard folder generated by Eclipse
proguard/
# Log Files
*.log
# Eclipse project files
.classpath
.project
.settings/
# Intellij project files
*.iml
*.ipr
*.iws
.idea/
# Mac system files
.DS_Store
*.keystore
================================================
FILE: README.md
================================================
:running:BGAFlowLayout-Android:running:
============
[](https://maven-badges.herokuapp.com/maven-central/cn.bingoogolapple/bga-flowlayout)
Android流式布局,可配置是否将每一行的空白区域平均分配给子控件。
最开始是参考[鸿洋_的这篇文章](http://blog.csdn.net/lmj623565791/article/details/38352503)的思路实现的,后来根据产品经理出的需求,增加了将每一行的空白区域平均分配给子控件。
demo中分别演示了在xml使用方式和在java代码中动态添加
### 效果图


### Gradle依赖
```groovy
dependencies {
compile 'cn.bingoogolapple:bga-flowlayout:latestVersion@aar'
}
```
### 自定义属性说明
```xml
```
## 作者联系方式
| 个人主页 | 邮箱 |
| ------------- | ------------ |
| bingoogolapple.cn | bingoogolapple@gmail.com |
| 个人微信号 | 微信群 | 公众号 |
| ------------ | ------------ | ------------ |
|
|
|
|
| 个人 QQ 号 | QQ 群 |
| ------------ | ------------ |
|
|
|
## 打赏支持作者
如果您觉得 BGA 系列开源库或工具软件帮您节省了大量的开发时间,可以扫描下方的二维码打赏支持。您的支持将鼓励我继续创作,打赏后还可以加我微信免费开通一年 [上帝小助手浏览器扩展/插件开发平台](https://github.com/bingoogolapple/bga-god-assistant-config) 的会员服务
| 微信 | QQ | 支付宝 |
| ------------- | ------------- | ------------- |
|
|
|
|
## 作者项目推荐
* 欢迎您使用我开发的第一个独立开发软件产品 [上帝小助手浏览器扩展/插件开发平台](https://github.com/bingoogolapple/bga-god-assistant-config)
================================================
FILE: build.gradle
================================================
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.0.0-alpha2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
================================================
FILE: demo/build.gradle
================================================
apply plugin: 'com.android.application'
android {
compileSdkVersion ANDROID_BUILD_SDK_VERSION as int
buildToolsVersion ANDROID_BUILD_TOOLS_VERSION
defaultConfig {
minSdkVersion ANDROID_BUILD_MIN_SDK_VERSION as int
targetSdkVersion ANDROID_BUILD_TARGET_SDK_VERSION as int
versionCode VERSION_CODE as int
versionName VERSION_NAME
}
}
dependencies {
compile 'com.android.support:appcompat-v7:23.1.1'
compile 'cn.bingoogolapple:bga-flowlayout:1.0.0@aar'
// compile project(':library')
}
================================================
FILE: demo/src/main/AndroidManifest.xml
================================================
================================================
FILE: demo/src/main/java/cn/bingoogolapple/flowlayout/demo/MainActivity.java
================================================
package cn.bingoogolapple.flowlayout.demo;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.TextView;
import cn.bingoogolapple.flowlayout.BGAFlowLayout;
public class MainActivity extends AppCompatActivity {
private String[] mVals = new String[]{"bingo", "googol", "apple", "bingoogolapple", "helloworld"};
private BGAFlowLayout mFlowLayout;
private EditText mTagEt;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTagEt = (EditText) findViewById(R.id.et_main_tag);
mFlowLayout = (BGAFlowLayout) findViewById(R.id.flowlayout);
initData();
mTagEt.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_GO) {
String tag = mTagEt.getText().toString().trim();
if (!TextUtils.isEmpty(tag)) {
mFlowLayout.addView(getLabel(tag), mFlowLayout.getChildCount() - 1, new ViewGroup.MarginLayoutParams(ViewGroup.MarginLayoutParams.WRAP_CONTENT, ViewGroup.MarginLayoutParams.WRAP_CONTENT));
}
mTagEt.setText("");
}
return true;
}
});
}
public void initData() {
for (int i = 0; i < mVals.length; i++) {
mFlowLayout.addView(getLabel(mVals[i]), mFlowLayout.getChildCount() - 1, new ViewGroup.MarginLayoutParams(ViewGroup.MarginLayoutParams.WRAP_CONTENT, ViewGroup.MarginLayoutParams.WRAP_CONTENT));
}
}
private TextView getLabel(String text) {
TextView label = new TextView(this);
label.setTextColor(Color.WHITE);
label.setBackgroundResource(R.drawable.selector_tag);
label.setGravity(Gravity.CENTER);
label.setSingleLine(true);
label.setEllipsize(TextUtils.TruncateAt.END);
int padding = BGAFlowLayout.dp2px(this, 5);
label.setPadding(padding, padding, padding, padding);
label.setText(text);
return label;
}
}
================================================
FILE: demo/src/main/res/drawable/selector_tag.xml
================================================
-
-
================================================
FILE: demo/src/main/res/drawable/shape_stroke_line.xml
================================================
================================================
FILE: demo/src/main/res/layout/activity_main.xml
================================================
================================================
FILE: demo/src/main/res/values/colors.xml
================================================
#f57257
#f46444
#f46444
#cccc
================================================
FILE: demo/src/main/res/values/strings.xml
================================================
BGAFlowLayoutDemo
================================================
FILE: demo/src/main/res/values/styles.xml
================================================
================================================
FILE: demo/src/main/res/values/styles_base.xml
================================================
================================================
FILE: demo/src/main/res/values-v21/styles.xml
================================================
================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
#Fri Dec 04 13:08:31 CST 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip
================================================
FILE: gradle.properties
================================================
ANDROID_BUILD_MIN_SDK_VERSION=10
ANDROID_BUILD_TARGET_SDK_VERSION=23
ANDROID_BUILD_SDK_VERSION=23
ANDROID_BUILD_TOOLS_VERSION=23.0.2
VERSION_NAME=1.0.0
VERSION_CODE=100
================================================
FILE: gradlew
================================================
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
================================================
FILE: gradlew.bat
================================================
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
================================================
FILE: library/build.gradle
================================================
apply plugin: 'com.android.library'
android {
compileSdkVersion ANDROID_BUILD_SDK_VERSION as int
buildToolsVersion ANDROID_BUILD_TOOLS_VERSION
defaultConfig {
minSdkVersion ANDROID_BUILD_MIN_SDK_VERSION as int
targetSdkVersion ANDROID_BUILD_TARGET_SDK_VERSION as int
}
}
// gradle uploadArchives
apply from: 'https://raw.githubusercontent.com/bingoogolapple/PublishAar/master/central-publish.gradle'
================================================
FILE: library/gradle.properties
================================================
PUBLISH_AAR_ARTIFACT_ID=bga-flowlayout
PUBLISH_AAR_DESCRIPTION=Android FlowLayout Library
PUBLISH_AAR_GITHUB_REPOSITORIES_NAME=BGAFlowLayout-Android
================================================
FILE: library/src/main/AndroidManifest.xml
================================================
================================================
FILE: library/src/main/java/cn/bingoogolapple/flowlayout/BGAFlowLayout.java
================================================
package cn.bingoogolapple.flowlayout;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;
/**
* 作者:王浩 邮件:bingoogolapple@gmail.com
* 创建时间:15/6/24 11:21
* 描述:流式布局
*/
public class BGAFlowLayout extends ViewGroup {
private List mRows = new ArrayList<>();
private int mHorizontalChildGap;
private int mVerticalChildGap;
private boolean mIsDistributionWhiteSpacing = true;
public BGAFlowLayout(Context context) {
this(context, null);
}
public BGAFlowLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public BGAFlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initDefaultAttrs(context);
initCustomAttrs(context, attrs);
}
private void initDefaultAttrs(Context context) {
mHorizontalChildGap = dp2px(context, 10);
mVerticalChildGap = dp2px(context, 10);
}
private void initCustomAttrs(Context context, AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.BGAFlowLayout);
final int N = typedArray.getIndexCount();
for (int i = 0; i < N; i++) {
initCustomAttr(typedArray.getIndex(i), typedArray);
}
typedArray.recycle();
}
private void initCustomAttr(int attr, TypedArray typedArray) {
if (attr == R.styleable.BGAFlowLayout_fl_horizontalChildGap) {
/**
* getDimension和getDimensionPixelOffset的功能差不多,都是获取某个dimen的值,如果是dp或sp的单位,将其乘以density,如果是px,则不乘;两个函数的区别是一个返回float,一个返回int. getDimensionPixelSize则不管写的是dp还是sp还是px,都会乘以denstiy.
*/
mHorizontalChildGap = typedArray.getDimensionPixelOffset(attr, mHorizontalChildGap);
} else if (attr == R.styleable.BGAFlowLayout_fl_verticalChildGap) {
mVerticalChildGap = typedArray.getDimensionPixelOffset(attr, mVerticalChildGap);
} else if (attr == R.styleable.BGAFlowLayout_fl_isDistributionWhiteSpacing) {
mIsDistributionWhiteSpacing = typedArray.getBoolean(attr, mIsDistributionWhiteSpacing);
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
/**
* 1.EXACTLY:100dp,match_parent
* 2.AT_MOST:wrap_content
* 3.UNSPCIFIED:子控件想要多大就多大,很少见(ScrollView)
*/
int modeHeight = MeasureSpec.getMode(heightMeasureSpec);
mRows.clear();
Row row = new Row(sizeWidth);
View child;
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
child = getChildAt(i);
measureChild(child, widthMeasureSpec, heightMeasureSpec);
if (!row.addChild(child)) {
mRows.add(row);
row = new Row(sizeWidth);
row.addChild(child);
}
}
// 添加最后一行
if (!mRows.contains(row)) {
mRows.add(row);
}
int height = 0;
int rowCount = mRows.size();
for (int i = 0; i < rowCount; i++) {
height += mRows.get(i).mHeight;
if (i != rowCount - 1) {
height += mVerticalChildGap;
}
}
setMeasuredDimension(sizeWidth, modeHeight == MeasureSpec.EXACTLY ? sizeHeight : height + getPaddingTop() + getPaddingBottom());
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int rowCount = mRows.size();
int top = getPaddingTop();
Row row;
for (int i = 0; i < rowCount; i++) {
row = mRows.get(i);
if (mIsDistributionWhiteSpacing && i != rowCount - 1) {
row.layout(true, top);
} else {
row.layout(false, top);
}
top += row.mHeight + mVerticalChildGap;
}
}
private class Row {
private List mViews = new ArrayList<>();
private int mWidth;
private int mNewWidth;
private int mHeight;
private int mMaxWidth;
public Row(int sizeWidth) {
mMaxWidth = sizeWidth - getPaddingLeft() - getPaddingRight();
}
public boolean addChild(View child) {
if (isOutOfMaxWidth(child.getMeasuredWidth())) {
return false;
} else {
mViews.add(child);
mWidth = mNewWidth;
int childHeight = child.getMeasuredHeight();
mHeight = mHeight < childHeight ? childHeight : mHeight;
return true;
}
}
private boolean isOutOfMaxWidth(int childWidth) {
if (mViews.size() == 0) {
mNewWidth = mWidth + childWidth;
} else {
mNewWidth = mWidth + mHorizontalChildGap + childWidth;
}
return mNewWidth > mMaxWidth;
}
/**
* @param isNeedSplit 是否需要平均分配空白区域给每一个子孩子
* @param top
*/
public void layout(boolean isNeedSplit, int top) {
if (mViews.size() == 0) {
return;
}
int left = getPaddingLeft();
int count = mViews.size();
int splitWidth = (mMaxWidth - mWidth) / count;
View view;
for (int i = 0; i < count; i++) {
view = mViews.get(i);
int childWidth = view.getMeasuredWidth();
int childHeight = view.getMeasuredHeight();
if (isNeedSplit) {
childWidth = childWidth + splitWidth;
view.getLayoutParams().width = childWidth;
if (splitWidth > 0) {
/**
* 1.EXACTLY:100dp,match_parent
* 2.AT_MOST:wrap_content
* 3.UNSPCIFIED:子控件想要多大就多大,很少见(ScrollView)
*/
int widthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY);
int heightMeasureSpec = MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY);
view.measure(widthMeasureSpec, heightMeasureSpec);
}
}
int topOffset = (int) ((mHeight - childHeight) / 2.0 + 0.5);
view.layout(left, top + topOffset, left + childWidth, top + topOffset + childHeight);
left += childWidth + mHorizontalChildGap;
}
}
}
public static int dp2px(Context context, float dpValue) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, context.getResources().getDisplayMetrics());
}
}
================================================
FILE: library/src/main/res/values/attrs.xml
================================================
================================================
FILE: settings.gradle
================================================
include ':library', ':demo'