Repository: huage2580/ZuiMeiTAG
Branch: master
Commit: 2a5005b406b6
Files: 34
Total size: 38.3 KB
Directory structure:
gitextract_zm55re4_/
├── .gitignore
├── .idea/
│ ├── .name
│ ├── compiler.xml
│ ├── copyright/
│ │ └── profiles_settings.xml
│ ├── encodings.xml
│ ├── gradle.xml
│ ├── misc.xml
│ ├── modules.xml
│ └── runConfigurations.xml
├── README.md
├── app/
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src/
│ ├── androidTest/
│ │ └── java/
│ │ └── com/
│ │ └── toxicant/
│ │ └── hua/
│ │ └── zuimeitag/
│ │ └── ApplicationTest.java
│ ├── main/
│ │ ├── AndroidManifest.xml
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── toxicant/
│ │ │ └── hua/
│ │ │ └── zuimeitag/
│ │ │ ├── MainActivity.java
│ │ │ ├── MyLayoutManager.java
│ │ │ └── TAGRecyclerView.java
│ │ └── res/
│ │ ├── drawable/
│ │ │ └── bg_white.xml
│ │ ├── layout/
│ │ │ ├── activity_main.xml
│ │ │ └── item.xml
│ │ ├── values/
│ │ │ ├── colors.xml
│ │ │ ├── dimens.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ └── values-w820dp/
│ │ └── dimens.xml
│ └── test/
│ └── java/
│ └── com/
│ └── toxicant/
│ └── hua/
│ └── zuimeitag/
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
================================================
FILE: .idea/.name
================================================
ZuiMeiTAG
================================================
FILE: .idea/compiler.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<resourceExtensions />
<wildcardResourcePatterns>
<entry name="!?*.java" />
<entry name="!?*.form" />
<entry name="!?*.class" />
<entry name="!?*.groovy" />
<entry name="!?*.scala" />
<entry name="!?*.flex" />
<entry name="!?*.kt" />
<entry name="!?*.clj" />
<entry name="!?*.aj" />
</wildcardResourcePatterns>
<annotationProcessing>
<profile default="true" name="Default" enabled="false">
<processorPath useClasspath="true" />
</profile>
</annotationProcessing>
</component>
</project>
================================================
FILE: .idea/copyright/profiles_settings.xml
================================================
<component name="CopyrightManager">
<settings default="" />
</component>
================================================
FILE: .idea/encodings.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="PROJECT" charset="UTF-8" />
</component>
</project>
================================================
FILE: .idea/gradle.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="distributionType" value="LOCAL" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleHome" value="E:\AndroidStudio\IDE3\gradle\gradle-2.10" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
<option name="myModules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>
================================================
FILE: .idea/misc.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EntryPointsManager">
<entry_points version="2.0" />
</component>
<component name="NullableNotNullManager">
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
<option name="myNullables">
<value>
<list size="4">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
</list>
</value>
</option>
<option name="myNotNulls">
<value>
<list size="4">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
</list>
</value>
</option>
</component>
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
<OptionsSetting value="true" id="Add" />
<OptionsSetting value="true" id="Remove" />
<OptionsSetting value="true" id="Checkout" />
<OptionsSetting value="true" id="Update" />
<OptionsSetting value="true" id="Status" />
<OptionsSetting value="true" id="Edit" />
<ConfirmationsSetting value="0" id="Add" />
<ConfirmationsSetting value="0" id="Remove" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.7" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>
================================================
FILE: .idea/modules.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/ZuiMeiTAG.iml" filepath="$PROJECT_DIR$/ZuiMeiTAG.iml" />
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
</modules>
</component>
</project>
================================================
FILE: .idea/runConfigurations.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
</set>
</option>
</component>
</project>
================================================
FILE: README.md
================================================
# ZuiMeiTAG
仿最美应用的底栏,使用recyclerView实现,相关博文http://www.jianshu.com/p/7202416974f6
能不能给个star鼓励下(●'◡'●)
#效果图

================================================
FILE: app/.gitignore
================================================
/build
================================================
FILE: app/build.gradle
================================================
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
applicationId "com.toxicant.hua.zuimeitag"
minSdkVersion 16
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.4.0'
compile 'com.android.support:recyclerview-v7:23.4.0'
}
================================================
FILE: app/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in E:\AndroidStudio\SDK/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
================================================
FILE: app/src/androidTest/java/com/toxicant/hua/zuimeitag/ApplicationTest.java
================================================
package com.toxicant.hua.zuimeitag;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
}
================================================
FILE: app/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.toxicant.hua.zuimeitag">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
================================================
FILE: app/src/main/java/com/toxicant/hua/zuimeitag/MainActivity.java
================================================
package com.toxicant.hua.zuimeitag;
import android.animation.ObjectAnimator;
import android.graphics.Bitmap;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
TAGRecyclerView rv;
Button btn1;
Button btn2;
ArrayList<String> datas;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn1= (Button) findViewById(R.id.button);
btn2= (Button) findViewById(R.id.button2);
rv= (TAGRecyclerView) findViewById(R.id.rv1);
rv.setLayoutManager(new MyLayoutManager());
datas=new ArrayList<>();
for (int i=0;i<20;i++){
datas.add("item==>"+i);
}
// final int temp=height/7;
final RvAdapter adapter = new RvAdapter();
rv.setAdapter(adapter);
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
rv.selectNextItem();
}
});
btn2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
rv.selectPreviousItem();
}
});
rv.setSwitchListener(new TAGRecyclerView.SwitchListener() {
@Override
public void onSwitch(int realIndex) {
Toast.makeText(MainActivity.this,"当前选择=>"+realIndex,Toast.LENGTH_SHORT).show();
}
});
}
class RvAdapter extends RecyclerView.Adapter<ViewHoler>{
@Override
public ViewHoler onCreateViewHolder(ViewGroup parent, int viewType) {
return new ViewHoler(LayoutInflater.from(parent.getContext()).inflate(R.layout.item,null,false));
}
@Override
public void onBindViewHolder(final ViewHoler holder, int position) {
holder.tv1.setText(datas.get(position));
}
@Override
public int getItemCount() {
return datas.size();
}
}
class ViewHoler extends RecyclerView.ViewHolder{
ImageView ivl;
TextView tv1;
LinearLayout ll;
public ViewHoler(View itemView) {
super(itemView);
ivl= (ImageView) itemView.findViewById(R.id.iv);
tv1= (TextView) itemView.findViewById(R.id.tv1);
ll= (LinearLayout) itemView.findViewById(R.id.linear_layout);
itemView.setClickable(false);
}
}
}
================================================
FILE: app/src/main/java/com/toxicant/hua/zuimeitag/MyLayoutManager.java
================================================
package com.toxicant.hua.zuimeitag;
import android.graphics.PointF;
import android.graphics.Rect;
import android.support.v7.widget.LinearSmoothScroller;
import android.support.v7.widget.RecyclerView;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.view.View;
import android.view.ViewGroup;
/**
* Created by hua on 2016.12.10.
*/
public class MyLayoutManager extends RecyclerView.LayoutManager {
public int mSelectIndex=0;
final int mPadding=3;
int allWidth=0;
int offsetScroll=0;
int firstView=0;//第一个可视view序号
boolean firstLayout=true;//每次开始布局
//保存所有的Item的上下左右的偏移量信息
private SparseArray<Rect> allItemFrames = new SparseArray<>();
//记录Item是否出现过屏幕且还没有回收。true表示出现过屏幕上,并且还没被回收
private SparseBooleanArray hasAttachedItems = new SparseBooleanArray();
@Override
public RecyclerView.LayoutParams generateDefaultLayoutParams() {
return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
detachAndScrapAttachedViews(recycler);
int offsetX=mPadding;
for(int i=0;i<getItemCount();i++){
View view=recycler.getViewForPosition(i);
// addView(view);
measureChildWithMargins(view,0,0);
int width = getDecoratedMeasuredWidth(view);
int height = getDecoratedMeasuredHeight(view);
// layoutDecorated(view,offsetX+mPadding,mPadding,offsetX+width-mPadding,height);
Rect frame = allItemFrames.get(i);
if (frame == null) {
frame = new Rect();
}
frame.set(offsetX,mPadding,offsetX+width,height);
// 将当前的Item的Rect边界数据保存
allItemFrames.put(i, frame);
// 由于已经调用了detachAndScrapAttachedViews,因此需要将当前的Item设置为未出现过
hasAttachedItems.put(i, false);
offsetX+=(width+mPadding*2);
}
allWidth=Math.max(getWidth()/7*getItemCount(),getWidth());
recyclerAndFillItems(recycler,state);
}
@Override
public void measureChildWithMargins(View child, int widthUsed, int heightUsed) {
final RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) child.getLayoutParams();
final int widthSpec = getChildMeasureSpec(getWidth(), getWidthMode(),
0, getWidth()/7-2*mPadding,
canScrollHorizontally());
final int heightSpec = getChildMeasureSpec(getHeight(), getHeightMode(),
0, lp.height,
canScrollVertically());
child.measure(widthSpec, heightSpec);
}
@Override
public boolean canScrollHorizontally() {
return true;
}
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
final int position) {
LinearSmoothScroller linearSmoothScroller =
new LinearSmoothScroller(recyclerView.getContext()) {
@Override
public PointF computeScrollVectorForPosition(int targetPosition) {
return MyLayoutManager.this.computeScrollVectorForPosition(position);
}
};
linearSmoothScroller.setTargetPosition(position);
startSmoothScroll(linearSmoothScroller);
}
public PointF computeScrollVectorForPosition(int targetPosition) {
if (getChildCount() == 0) {
return null;
}
final int firstChildPos = getPosition(getChildAt(0));
final int direction = targetPosition < firstChildPos? -1 : 1;
return new PointF(direction, 0);
}
@Override
public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
//先detach掉所有的子View
detachAndScrapAttachedViews(recycler);
//实际要滑动的距离
int travel = dx;
if (offsetScroll+dx<0){//滑动到最左边
travel=-offsetScroll;
}else if(offsetScroll+dx>allWidth-getWidth()){//最右边
travel=allWidth-getWidth()-offsetScroll;
}
offsetScroll+=travel;
offsetChildrenHorizontal(-travel);
recyclerAndFillItems(recycler, state);
return travel;
}
void recyclerAndFillItems(RecyclerView.Recycler recycler, RecyclerView.State state){
if (state.isPreLayout()) { // 跳过preLayout,preLayout主要用于支持动画
return;
}
// 当前scroll offset状态下的显示区域
Rect displayFrame = new Rect(offsetScroll,0, getWidth()+offsetScroll, getHeight());
// Log.e("display","left->"+displayFrame.left+"right->"+displayFrame.right);
//回收
Rect childFrame = new Rect();
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
childFrame.left = getDecoratedLeft(child);
childFrame.top = getDecoratedTop(child);
childFrame.right = getDecoratedRight(child);
childFrame.bottom = getDecoratedBottom(child);
// Log.e("回收判断","left->"+childFrame.left+"right->"+childFrame.right);
//如果Item没有在显示区域,就说明需要回收
if (!Rect.intersects(displayFrame, childFrame)) {
//回收掉滑出屏幕的View
removeAndRecycleView(child, recycler);
}
}
//显示
firstLayout=true;
for (int i = 0; i < getItemCount(); i++) {
if (Rect.intersects(displayFrame, allItemFrames.get(i))) {
// Log.e("layout","显示==>"+i);
if(firstLayout){
firstView=i;
firstLayout=false;
}
View scrap = recycler.getViewForPosition(i);
measureChildWithMargins(scrap, 0, 0);
int height = getDecoratedMeasuredHeight(scrap);
if (i!=mSelectIndex){
scrap.setTranslationY(height/7*6);
}
addView(scrap);
Rect frame = allItemFrames.get(i);
// Log.e("显示判断","left->"+frame.left+"right->"+frame.right);
//将这个item布局出来
layoutDecorated(scrap,
frame.left-offsetScroll,
frame.top,
frame.right-offsetScroll,
frame.bottom);
}
}
}
}
================================================
FILE: app/src/main/java/com/toxicant/hua/zuimeitag/TAGRecyclerView.java
================================================
package com.toxicant.hua.zuimeitag;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
/**
* Created by hua on 2016.12.11.
*/
public class TAGRecyclerView extends RecyclerView implements View.OnTouchListener {
private int mOffsetIndex;//偏移量,显示的第一个view的序号 [0,n)
private int mSelectIndex;//当前选择的真实序号 [0,n)
private SwitchListener mSwitchListener;
interface SwitchListener{
void onSwitch(int realIndex);
}
public TAGRecyclerView(Context context) {
super(context);
init();
}
public TAGRecyclerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public TAGRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
void init(){
mOffsetIndex=0;
mSelectIndex=0;
setOnTouchListener(this);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
float x=event.getX();
final int index= (int) (x/(this.getWidth()/7));
//Log.i("index","index->"+index);
switch (action){
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
final int th=this.getHeight()/7;
//view突出
for (int i=0;i<7;i++){
int t=Math.abs(index-i);
// Log.i("突出","点击->"+index+"当前相距->"+t+"第一个view:"+count);
this.getChildAt(i).setTranslationY(t*th);
}
break;
case MotionEvent.ACTION_UP:
//记录位置
RecyclerView.LayoutManager lm= this.getLayoutManager();
if (lm instanceof MyLayoutManager){
mOffsetIndex = ((MyLayoutManager) lm).firstView;
mSelectIndex=mOffsetIndex+index;
((MyLayoutManager) lm).mSelectIndex=mSelectIndex;
//Log.i("up","抬起相对位置-"+index+"偏移量-"+mOffsetIndex+"选择的真实序号-"+mSelectIndex);
}
if (mSwitchListener!=null){
mSwitchListener.onSwitch(mSelectIndex);
}
boolean isFirstAnim=true;
//下落动画
for (int i=0;i<7;i++){
if (i==index){
continue;
}
View temp=this.getChildAt(i);
ObjectAnimator anim=ObjectAnimator//
.ofFloat(temp, "TranslationY", temp.getTranslationY(),this.getHeight()/7*6)//
.setDuration(500);
anim.start();
if (isFirstAnim){
anim.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
//位移动画
scrollItem(index);
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
isFirstAnim=false;
}
}
break;
}
return true;
}
/**
* 把这个item放到中间,是相对序号
* @param index 对应屏幕上的第几个[0,n)
*/
private void scrollItem(int index){
int dx=0;
final int tw=TAGRecyclerView.this.getWidth()/7;
if (index<3){
dx=-tw*(3-index);
}else if(index>3){
dx=tw*(index-3);
}
TAGRecyclerView.this.smoothScrollBy(dx,0);
}
/**
* 切换到下一个item
*/
public boolean selectNextItem(){
if (mSelectIndex>=TAGRecyclerView.this.getAdapter().getItemCount()-1){//已经是最后一个
return false;
}
//当前选择的item下落
final RecyclerView.LayoutManager lm= this.getLayoutManager();
if (lm instanceof MyLayoutManager) {
mOffsetIndex = ((MyLayoutManager) lm).firstView;
View view=this.getChildAt(mSelectIndex-mOffsetIndex);
final ObjectAnimator anim=ObjectAnimator.ofFloat(view, "TranslationY", view.getTranslationY(),this.getHeight()/7*6)
.setDuration(200);
anim.start();
anim.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
//下一个item升起
mSelectIndex+=1;
((MyLayoutManager) lm).mSelectIndex=mSelectIndex;
View view=TAGRecyclerView.this.getChildAt(mSelectIndex-mOffsetIndex);
ObjectAnimator animR=ObjectAnimator.ofFloat(view, "TranslationY", view.getTranslationY(),0)
.setDuration(200);
animR.start();
animR.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
scrollItem(mSelectIndex-mOffsetIndex);
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
}
return true;
}
/**
* 切换到上一个item
*/
public boolean selectPreviousItem(){
if (mSelectIndex<1){//已经是第一个
return false;
}
//当前选择的item下落
final RecyclerView.LayoutManager lm= this.getLayoutManager();
if (lm instanceof MyLayoutManager) {
mOffsetIndex = ((MyLayoutManager) lm).firstView;
View view=this.getChildAt(mSelectIndex-mOffsetIndex);
final ObjectAnimator anim=ObjectAnimator.ofFloat(view, "TranslationY", view.getTranslationY(),this.getHeight()/7*6)
.setDuration(200);
anim.start();
anim.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
//上一个item升起
mSelectIndex-=1;
((MyLayoutManager) lm).mSelectIndex=mSelectIndex;
View view=TAGRecyclerView.this.getChildAt(mSelectIndex-mOffsetIndex);
ObjectAnimator animR=ObjectAnimator.ofFloat(view, "TranslationY", view.getTranslationY(),0)
.setDuration(200);
animR.start();
animR.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
scrollItem(mSelectIndex-mOffsetIndex);
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
}
return true;
}
/**
* 当前选择的item真实序号
* @return
*/
public int getSelectIndex(){
return mSelectIndex;
}
public void setSwitchListener(SwitchListener listener){
this.mSwitchListener=listener;
}
}
================================================
FILE: app/src/main/res/drawable/bg_white.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners
android:topLeftRadius="10dp"
android:topRightRadius="10dp">
</corners>
<solid android:color="#ffffff">
</solid>
</shape>
================================================
FILE: app/src/main/res/layout/activity_main.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorAccent"
tools:context="com.toxicant.hua.zuimeitag.MainActivity">
<com.toxicant.hua.zuimeitag.TAGRecyclerView
android:id="@+id/rv1"
android:layout_width="match_parent"
android:layout_height="80dp"
android:layout_alignParentBottom="true">
</com.toxicant.hua.zuimeitag.TAGRecyclerView>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下一个"
android:id="@+id/button"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="上一个"
android:id="@+id/button2"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true" />
</RelativeLayout>
================================================
FILE: app/src/main/res/layout/item.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="80dp">
<LinearLayout
android:id="@+id/linear_layout"
android:orientation="vertical"
android:padding="5dp"
android:clickable="false"
android:background="@drawable/bg_white"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/iv"
android:src="@drawable/logo1"
android:layout_width="match_parent"
android:layout_height="35dp" />
<TextView
android:id="@+id/tv1"
tools:text="666"
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</FrameLayout>
================================================
FILE: app/src/main/res/values/colors.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
</resources>
================================================
FILE: app/src/main/res/values/dimens.xml
================================================
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
</resources>
================================================
FILE: app/src/main/res/values/strings.xml
================================================
<resources>
<string name="app_name">ZuiMeiTAG</string>
</resources>
================================================
FILE: app/src/main/res/values/styles.xml
================================================
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>
================================================
FILE: app/src/main/res/values-w820dp/dimens.xml
================================================
<resources>
<!-- Example customization of dimensions originally defined in res/values/dimens.xml
(such as screen margins) for screens with more than 820dp of available width. This
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
<dimen name="activity_horizontal_margin">64dp</dimen>
</resources>
================================================
FILE: app/src/test/java/com/toxicant/hua/zuimeitag/ExampleUnitTest.java
================================================
package com.toxicant.hua.zuimeitag;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* To work on unit tests, switch the Test Artifact in the Build Variants view.
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}
================================================
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'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
#Mon Dec 28 10:00:20 PST 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
================================================
FILE: gradle.properties
================================================
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
================================================
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
# 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\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
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"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# 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: settings.gradle
================================================
include ':app'
gitextract_zm55re4_/ ├── .gitignore ├── .idea/ │ ├── .name │ ├── compiler.xml │ ├── copyright/ │ │ └── profiles_settings.xml │ ├── encodings.xml │ ├── gradle.xml │ ├── misc.xml │ ├── modules.xml │ └── runConfigurations.xml ├── README.md ├── app/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── toxicant/ │ │ └── hua/ │ │ └── zuimeitag/ │ │ └── ApplicationTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── toxicant/ │ │ │ └── hua/ │ │ │ └── zuimeitag/ │ │ │ ├── MainActivity.java │ │ │ ├── MyLayoutManager.java │ │ │ └── TAGRecyclerView.java │ │ └── res/ │ │ ├── drawable/ │ │ │ └── bg_white.xml │ │ ├── layout/ │ │ │ ├── activity_main.xml │ │ │ └── item.xml │ │ ├── values/ │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ └── values-w820dp/ │ │ └── dimens.xml │ └── test/ │ └── java/ │ └── com/ │ └── toxicant/ │ └── hua/ │ └── zuimeitag/ │ └── ExampleUnitTest.java ├── build.gradle ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat └── settings.gradle
SYMBOL INDEX (34 symbols across 5 files)
FILE: app/src/androidTest/java/com/toxicant/hua/zuimeitag/ApplicationTest.java
class ApplicationTest (line 9) | public class ApplicationTest extends ApplicationTestCase<Application> {
method ApplicationTest (line 10) | public ApplicationTest() {
FILE: app/src/main/java/com/toxicant/hua/zuimeitag/MainActivity.java
class MainActivity (line 24) | public class MainActivity extends AppCompatActivity {
method onCreate (line 29) | @Override
class RvAdapter (line 65) | class RvAdapter extends RecyclerView.Adapter<ViewHoler>{
method onCreateViewHolder (line 67) | @Override
method onBindViewHolder (line 72) | @Override
method getItemCount (line 77) | @Override
class ViewHoler (line 83) | class ViewHoler extends RecyclerView.ViewHolder{
method ViewHoler (line 87) | public ViewHoler(View itemView) {
FILE: app/src/main/java/com/toxicant/hua/zuimeitag/MyLayoutManager.java
class MyLayoutManager (line 15) | public class MyLayoutManager extends RecyclerView.LayoutManager {
method generateDefaultLayoutParams (line 26) | @Override
method onLayoutChildren (line 31) | @Override
method measureChildWithMargins (line 59) | @Override
method canScrollHorizontally (line 72) | @Override
method smoothScrollToPosition (line 77) | @Override
method computeScrollVectorForPosition (line 91) | public PointF computeScrollVectorForPosition(int targetPosition) {
method scrollHorizontallyBy (line 102) | @Override
method recyclerAndFillItems (line 119) | void recyclerAndFillItems(RecyclerView.Recycler recycler, RecyclerView...
FILE: app/src/main/java/com/toxicant/hua/zuimeitag/TAGRecyclerView.java
class TAGRecyclerView (line 16) | public class TAGRecyclerView extends RecyclerView implements View.OnTouc...
type SwitchListener (line 21) | interface SwitchListener{
method onSwitch (line 22) | void onSwitch(int realIndex);
method TAGRecyclerView (line 24) | public TAGRecyclerView(Context context) {
method TAGRecyclerView (line 29) | public TAGRecyclerView(Context context, @Nullable AttributeSet attrs) {
method TAGRecyclerView (line 34) | public TAGRecyclerView(Context context, @Nullable AttributeSet attrs, ...
method init (line 39) | void init(){
method onTouch (line 45) | @Override
method scrollItem (line 122) | private void scrollItem(int index){
method selectNextItem (line 136) | public boolean selectNextItem(){
method selectPreviousItem (line 203) | public boolean selectPreviousItem(){
method getSelectIndex (line 272) | public int getSelectIndex(){
method setSwitchListener (line 275) | public void setSwitchListener(SwitchListener listener){
FILE: app/src/test/java/com/toxicant/hua/zuimeitag/ExampleUnitTest.java
class ExampleUnitTest (line 10) | public class ExampleUnitTest {
method addition_isCorrect (line 11) | @Test
Condensed preview — 34 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (44K chars).
[
{
"path": ".gitignore",
"chars": 97,
"preview": "*.iml\n.gradle\n/local.properties\n/.idea/workspace.xml\n/.idea/libraries\n.DS_Store\n/build\n/captures\n"
},
{
"path": ".idea/.name",
"chars": 9,
"preview": "ZuiMeiTAG"
},
{
"path": ".idea/compiler.xml",
"chars": 686,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"CompilerConfiguration\">\n <resourceExt"
},
{
"path": ".idea/copyright/profiles_settings.xml",
"chars": 74,
"preview": "<component name=\"CopyrightManager\">\n <settings default=\"\" />\n</component>"
},
{
"path": ".idea/encodings.xml",
"chars": 159,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"Encoding\">\n <file url=\"PROJECT\" chars"
},
{
"path": ".idea/gradle.xml",
"chars": 815,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"GradleSettings\">\n <option name=\"linke"
},
{
"path": ".idea/misc.xml",
"chars": 2226,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"EntryPointsManager\">\n <entry_points v"
},
{
"path": ".idea/modules.xml",
"chars": 355,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"ProjectModuleManager\">\n <modules>\n "
},
{
"path": ".idea/runConfigurations.xml",
"chars": 564,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n <component name=\"RunConfigurationProducerService\">\n <o"
},
{
"path": "README.md",
"chars": 176,
"preview": "# ZuiMeiTAG\n仿最美应用的底栏,使用recyclerView实现,相关博文http://www.jianshu.com/p/7202416974f6 \n能不能给个star鼓励下(●'◡'●)\n#效果图\n users:\n# Gradle settings configured through the IDE *will o"
},
{
"path": "gradlew",
"chars": 4971,
"preview": "#!/usr/bin/env bash\n\n##############################################################################\n##\n## Gradle start "
},
{
"path": "gradlew.bat",
"chars": 2314,
"preview": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem "
},
{
"path": "settings.gradle",
"chars": 15,
"preview": "include ':app'\n"
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the huage2580/ZuiMeiTAG GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 34 files (38.3 KB), approximately 10.5k tokens, and a symbol index with 34 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.