├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── github │ │ └── qing │ │ └── multtypeimagelayout │ │ ├── HomeActivity.java │ │ ├── NewsActivity.java │ │ ├── adapter │ │ ├── MultiImgAdapter.java │ │ └── RecommendCardAdapter.java │ │ ├── data │ │ ├── ContentData.java │ │ ├── DataFactory.java │ │ ├── HotData.java │ │ ├── ImageUrl.java │ │ ├── JikeData.java │ │ ├── RecommendData.java │ │ ├── RecommendList.java │ │ └── WeatherData.java │ │ ├── manager │ │ └── ImgGridLayoutManager.java │ │ ├── photo │ │ ├── LazyFragment.java │ │ ├── PhotoActivity.java │ │ ├── PhotoFragment.java │ │ ├── PhotoViewPager.java │ │ └── SmoothImageView.java │ │ ├── utils │ │ ├── DisplayUtils.java │ │ └── ImageLoader.java │ │ └── viewbinder │ │ ├── BaseContentViewBinder.java │ │ ├── ContentDataType.java │ │ ├── HotViewBinder.java │ │ ├── MultiImgViewBinder.java │ │ ├── MusicViewBinder.java │ │ ├── RecommendViewBinder.java │ │ ├── SingleImgViewBinder.java │ │ ├── TextContentViewBInder.java │ │ ├── VideoViewBinder.java │ │ └── WeatherViewBinder.java │ └── res │ ├── drawable │ ├── blue_button.xml │ ├── card_shape.xml │ ├── indicator_shape.xml │ └── tag_shape.xml │ ├── layout │ ├── activity_home.xml │ ├── activity_news.xml │ ├── activity_photo.xml │ ├── fragment_photo_layout.xml │ ├── include_line.xml │ ├── item_base_content_layout.xml │ ├── item_content_single_image.xml │ ├── item_hot_layout.xml │ ├── item_image.xml │ ├── item_mult_img_layout.xml │ ├── item_music_layout.xml │ ├── item_recommend_card_layout.xml │ ├── item_recommend_layout.xml │ ├── item_video_layout.xml │ └── item_weather_layout.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── arow_right.png │ ├── arrow_down.png │ ├── close.png │ ├── delete.png │ ├── heart.png │ ├── hot.png │ ├── ic_launcher.png │ ├── ic_launcher_round.png │ ├── link.png │ ├── local.png │ ├── message.png │ ├── music.png │ ├── play.png │ ├── play_gray.png │ ├── plus.png │ ├── share.png │ ├── weather01.png │ ├── weather02.png │ ├── weather03.png │ ├── weather04.png │ └── weather05.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | /.idea 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### MultiTypeImageLayout 2 | 3 | > 该项目是一个`Demo`项目,主要用来实现列表中多个`Item`展现,九宫格图片展示,以及类似微信的多图预览等功能。之所以没有做成`Lib`是由于有些实现需要根据项目的不同需求去修改,如:九宫格的展现方式,图片点击后的其他处理等,抽取出来如果有其他需求,还得在抽取的代码中修改。所以决定放在`Demo`中实现所有的功能。`Demo`中许多细节也都处理过,所以可以作为一种实现参考。 4 | 5 | #### 多Item列表 6 | 7 | 列表界面仿`即刻APP`的消息列表页,里面包含不同的`Item`布局,使用[**MultiType**](https://github.com/drakeet/MultiType)实现,该`Lib`提供了详细的使用文档,对于多`Item`布局非常方便。 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | #### 九宫格图片展示 22 | 23 | 九宫格图片展示其实使用的是`GridLayoutManager`中提供的`setSpanSizeLookup()`方法,用来设置每个`Item`占据的`Span`。具体可参考`ImgGridLayoutManager`类。 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
35 | 36 | #### 图片预览 37 | 38 | 图片预览效果类似与微信的图片预览,进入预览时有共享动画,可**拖动退出图片预览**。由于`Gif`过大所以只能放置链接。 39 | 40 | [图片预览转场动画](http://onxvhxvw6.bkt.clouddn.com/image/multiTypeImage/4%E6%9C%88-14-2017%2016-15-08.gif) 41 | 42 | [拖动图片退出预览动画](http://onxvhxvw6.bkt.clouddn.com/image/multiTypeImage/4%E6%9C%88-14-2017%2016-18-26.gif) 43 | 44 | 图片预览的处理实现,使用[**WeixinPhotoViewer**](https://github.com/nirvanawoody/WeixinPhotoViewer),它是在`PhotoView`的基础上实现了预览时类似与微信的转场效果。该`Demo`在此基础上添加了拖动退出图片预览的功能。 45 | 46 | #### 感谢 47 | 48 | `Demo`主要使用了`MultiType`和`WeixinPhotoViewer`并在此基础上根据自己的需求进行了改造。特此感谢。 49 | 50 | 1. [**MultiType**](https://github.com/drakeet/MultiType) 51 | 2. [**WeixinPhotoViewer**](https://github.com/nirvanawoody/WeixinPhotoViewer) -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.2" 6 | defaultConfig { 7 | applicationId "com.github.qing.multtypeimagelayout" 8 | minSdkVersion 15 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | compile 'com.android.support:appcompat-v7:25.3.0' 23 | compile 'com.android.support:recyclerview-v7:25.3.0' 24 | compile 'com.github.dcq123:SimpleItemDecoration:v0.0.1' 25 | 26 | compile 'com.github.bumptech.glide:glide:3.7.0' 27 | compile 'jp.wasabeef:glide-transformations:2.0.2' 28 | 29 | compile 'me.drakeet.multitype:multitype:2.5.0' 30 | 31 | compile 'com.jakewharton:butterknife:8.5.1' 32 | annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1' 33 | 34 | compile 'com.github.chrisbanes:PhotoView:2.0.0' 35 | 36 | compile 'com.pnikosis:materialish-progress:1.7' 37 | } 38 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/dingchangqing/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 24 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/qing/multtypeimagelayout/HomeActivity.java: -------------------------------------------------------------------------------- 1 | package com.github.qing.multtypeimagelayout; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.NonNull; 5 | import android.support.v4.widget.SwipeRefreshLayout; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.support.v7.widget.RecyclerView; 8 | 9 | import com.github.qing.itemdecoration.LinearDividerItemDecoration; 10 | import com.github.qing.multtypeimagelayout.data.DataFactory; 11 | import com.github.qing.multtypeimagelayout.data.HotData; 12 | import com.github.qing.multtypeimagelayout.data.RecommendList; 13 | import com.github.qing.multtypeimagelayout.data.WeatherData; 14 | import com.github.qing.multtypeimagelayout.viewbinder.ContentDataType; 15 | import com.github.qing.multtypeimagelayout.viewbinder.HotViewBinder; 16 | import com.github.qing.multtypeimagelayout.viewbinder.MultiImgViewBinder; 17 | import com.github.qing.multtypeimagelayout.viewbinder.MusicViewBinder; 18 | import com.github.qing.multtypeimagelayout.viewbinder.RecommendViewBinder; 19 | import com.github.qing.multtypeimagelayout.viewbinder.SingleImgViewBinder; 20 | import com.github.qing.multtypeimagelayout.viewbinder.TextContentViewBInder; 21 | import com.github.qing.multtypeimagelayout.viewbinder.VideoViewBinder; 22 | import com.github.qing.multtypeimagelayout.viewbinder.WeatherViewBinder; 23 | 24 | import java.util.ArrayList; 25 | import java.util.List; 26 | 27 | import butterknife.BindView; 28 | import butterknife.ButterKnife; 29 | import me.drakeet.multitype.FlatTypeClassAdapter; 30 | import me.drakeet.multitype.MultiTypeAdapter; 31 | 32 | public class HomeActivity extends AppCompatActivity { 33 | 34 | @BindView(R.id.refreshLayout) 35 | SwipeRefreshLayout refreshLayout; 36 | @BindView(R.id.recyclerView) 37 | RecyclerView recyclerView; 38 | MultiTypeAdapter adapter; 39 | List items = new ArrayList<>(); 40 | 41 | @Override 42 | protected void onCreate(Bundle savedInstanceState) { 43 | super.onCreate(savedInstanceState); 44 | setContentView(R.layout.activity_home); 45 | 46 | ButterKnife.bind(this); 47 | 48 | adapter = new MultiTypeAdapter(); 49 | 50 | // 注册所有的item类型 51 | adapter.register(HotData.class, new HotViewBinder()); 52 | adapter.register(WeatherData.class, new WeatherViewBinder()); 53 | adapter.register(RecommendList.class, new RecommendViewBinder()); 54 | // 对于常规的内容Item,根据其是音频,图片,还是视频,进行1对多的Item映射 55 | adapter.register(ContentDataType.Text.class, new TextContentViewBInder()); 56 | adapter.register(ContentDataType.SingleImage.class, new SingleImgViewBinder()); 57 | adapter.register(ContentDataType.MultiImage.class, new MultiImgViewBinder()); 58 | adapter.register(ContentDataType.Music.class, new MusicViewBinder()); 59 | adapter.register(ContentDataType.Video.class, new VideoViewBinder()); 60 | 61 | // 定义 MultiType 的类型转换 62 | adapter.setFlatTypeAdapter(new FlatTypeClassAdapter() { 63 | @NonNull 64 | @Override 65 | public Class onFlattenClass(@NonNull Object item) { 66 | // 当item为ContentDataType时,需要获取其映射的类型 67 | if (item instanceof ContentDataType) { 68 | return ((ContentDataType) item).getTypeClass(); 69 | } 70 | return item.getClass(); 71 | } 72 | }); 73 | 74 | // 添加列表分隔符 75 | recyclerView.addItemDecoration( 76 | new LinearDividerItemDecoration.Builder() 77 | .setDividerHeight(16) 78 | .setDividerColor(getResources().getColor(R.color.space_bg_color)) 79 | .build() 80 | ); 81 | 82 | recyclerView.setAdapter(adapter); 83 | 84 | loadData(); 85 | initRefreshLayout(); 86 | 87 | } 88 | 89 | private void initRefreshLayout() { 90 | refreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { 91 | @Override 92 | public void onRefresh() { 93 | refreshLayout.setRefreshing(true); 94 | refreshLayout.postDelayed(new Runnable() { 95 | @Override 96 | public void run() { 97 | loadData(); 98 | refreshLayout.setRefreshing(false); 99 | } 100 | }, 2000); 101 | } 102 | }); 103 | refreshLayout.setColorSchemeColors(getResources().getColor(R.color.colorPrimary), getResources().getColor(R.color.colorAccent)); 104 | } 105 | 106 | private void loadData() { 107 | items.clear(); 108 | items.addAll(DataFactory.createData()); 109 | adapter.setItems(items); 110 | adapter.notifyDataSetChanged(); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/qing/multtypeimagelayout/NewsActivity.java: -------------------------------------------------------------------------------- 1 | package com.github.qing.multtypeimagelayout; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.ActionBar; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.text.TextUtils; 7 | import android.webkit.WebView; 8 | import android.webkit.WebViewClient; 9 | 10 | import butterknife.BindView; 11 | import butterknife.ButterKnife; 12 | 13 | public class NewsActivity extends AppCompatActivity { 14 | 15 | public static final String KEY_TITLE = "title"; 16 | public static final String KEY_URL = "url"; 17 | 18 | @BindView(R.id.webView) 19 | WebView webView; 20 | 21 | @Override 22 | protected void onCreate(Bundle savedInstanceState) { 23 | super.onCreate(savedInstanceState); 24 | setContentView(R.layout.activity_news); 25 | ButterKnife.bind(this); 26 | 27 | initWebView(); 28 | 29 | String url = getIntent().getStringExtra(KEY_URL); 30 | String title = getIntent().getStringExtra(KEY_TITLE); 31 | setTitle(title); 32 | ActionBar supportActionBar = getSupportActionBar(); 33 | if (supportActionBar != null) { 34 | supportActionBar.setHomeButtonEnabled(true); 35 | supportActionBar.setDisplayHomeAsUpEnabled(true); 36 | } 37 | if (!TextUtils.isEmpty(url)) { 38 | webView.loadUrl(url); 39 | } 40 | } 41 | 42 | private void initWebView() { 43 | webView.setWebViewClient(new WebViewClient() { 44 | @Override 45 | public boolean shouldOverrideUrlLoading(WebView view, String url) { 46 | view.loadUrl(url); 47 | return true; 48 | } 49 | }); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/qing/multtypeimagelayout/adapter/MultiImgAdapter.java: -------------------------------------------------------------------------------- 1 | package com.github.qing.multtypeimagelayout.adapter; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.ImageView; 10 | 11 | import com.bumptech.glide.Glide; 12 | import com.bumptech.glide.request.animation.GlideAnimation; 13 | import com.bumptech.glide.request.target.SimpleTarget; 14 | import com.github.qing.multtypeimagelayout.R; 15 | import com.github.qing.multtypeimagelayout.data.ContentData; 16 | import com.github.qing.multtypeimagelayout.data.ImageUrl; 17 | import com.github.qing.multtypeimagelayout.manager.ImgGridLayoutManager; 18 | import com.github.qing.multtypeimagelayout.utils.DisplayUtils; 19 | 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | 23 | import butterknife.BindView; 24 | import butterknife.ButterKnife; 25 | 26 | /** 27 | * Created by dcq on 2017/4/10. 28 | *

29 | * 9宫格图片布局Adapter 30 | */ 31 | 32 | public class MultiImgAdapter extends RecyclerView.Adapter { 33 | private int itemViewWidth = 0; 34 | private List data = new ArrayList<>(); 35 | 36 | private ImgGridLayoutManager layoutManager; 37 | private RecyclerView recyclerView; 38 | private OnImageClickListener listener; 39 | 40 | public MultiImgAdapter(RecyclerView recyclerView) { 41 | this.recyclerView = recyclerView; 42 | this.layoutManager = (ImgGridLayoutManager) recyclerView.getLayoutManager(); 43 | } 44 | 45 | public void setData(List data) { 46 | this.data.clear(); 47 | this.data.addAll(data); 48 | } 49 | 50 | @Override 51 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 52 | return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_image, parent, false)); 53 | } 54 | 55 | @Override 56 | public void onBindViewHolder(final ViewHolder holder, int position) { 57 | ContentData.ImgBean imgBean = data.get(position); 58 | Context context = holder.itemView.getContext(); 59 | // 获取9宫格itemView的宽度 60 | if (itemViewWidth == 0) { 61 | itemViewWidth = recyclerView.getMeasuredWidth() - recyclerView.getPaddingLeft() - recyclerView.getPaddingRight(); 62 | } 63 | if (itemViewWidth == 0) { 64 | itemViewWidth = (int) (DisplayUtils.getScreenWH(context).x - context.getResources().getDimension(R.dimen.item_padding) * 2); 65 | } 66 | // 根据Grid item 的位置,重新设置图片的宽高 67 | ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) holder.imageView.getLayoutParams(); 68 | int spanSize = layoutManager.getSpanSizeLookup().getSpanSize(position); 69 | // 占据一整行的item,高度设置为宽度的0.4 70 | if (spanSize == ImgGridLayoutManager.SPAN_SIZE) { 71 | if (itemViewWidth != 0) { 72 | layoutParams.height = (int) (itemViewWidth * 0.4f); 73 | holder.imageView.requestLayout(); 74 | } 75 | } else { 76 | // 其他行的Item,宽高设置为相等 77 | if (itemViewWidth != 0) { 78 | int count = ImgGridLayoutManager.SPAN_SIZE / spanSize; 79 | layoutParams.height = (itemViewWidth - (layoutParams.leftMargin - layoutParams.rightMargin) * count) / count - layoutParams.topMargin - layoutParams.bottomMargin; 80 | holder.imageView.requestLayout(); 81 | } 82 | } 83 | final String url = ImageUrl.webplUrl(imgBean.getUrl()); 84 | holder.imageView.setTag(url); 85 | 86 | 87 | /** 88 | * 89 | * 此处注释原有Glide直接加载并显示到ImageView中的方式,而使用下载图片,并手动设置到ImageView上。 90 | * 其原因是:Glide缓存策略中使用的key是根据4部分组成 91 | * 1.DataFetcher的方法getId()返回的字符,通常是我们指定的url 92 | * 2.宽和高。如果你调用过override(width,height)方法,那么就是是它传入的值。没有调用过,默认是通过Target的getSize()方法获得这个值。 93 | * 3.各种编码器、解码器的getId()方法返回的字符串。 94 | * 4.可选地,你可以为图片加载提供签名(Signature) 95 | * 96 | * 以上组成key的4部分,确定了另一个ImageView加载图片时,能否去使用缓存中的数据, 97 | * 在点击小图,平滑移动到photoView中进行预览时,由于size已经不同,所以在photoView展现图片时,并未使用到缓存的数据,这就导致过渡动画无法展现 98 | * 所以在此,直接使用图片下载的方式,来公用缓存的图片数据 99 | * 100 | */ 101 | // ImageLoader.loadImage(holder.itemView.getContext().getApplicationContext(), ImageUrl.webplUrl(imgBean.getUrl()), holder.imageView); 102 | Glide.with(holder.itemView.getContext()) 103 | .load(url) 104 | .asBitmap() 105 | .into(new SimpleTarget() { 106 | @Override 107 | public void onResourceReady(Bitmap resource, GlideAnimation glideAnimation) { 108 | Object tag = holder.imageView.getTag(); 109 | if (tag != null && tag.equals(url)) { 110 | holder.imageView.setImageBitmap(resource); 111 | } 112 | } 113 | }); 114 | } 115 | 116 | @Override 117 | public int getItemCount() { 118 | return data.size(); 119 | } 120 | 121 | public interface OnImageClickListener { 122 | void onImageClick(int position); 123 | } 124 | 125 | public void setListener(OnImageClickListener listener) { 126 | this.listener = listener; 127 | } 128 | 129 | class ViewHolder extends RecyclerView.ViewHolder { 130 | 131 | @BindView(R.id.imageView) 132 | ImageView imageView; 133 | 134 | ViewHolder(final View itemView) { 135 | super(itemView); 136 | ButterKnife.bind(this, itemView); 137 | 138 | imageView.setOnClickListener(new View.OnClickListener() { 139 | @Override 140 | public void onClick(View v) { 141 | if (listener != null && v instanceof ImageView) { 142 | listener.onImageClick(getAdapterPosition()); 143 | } 144 | } 145 | }); 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/qing/multtypeimagelayout/adapter/RecommendCardAdapter.java: -------------------------------------------------------------------------------- 1 | package com.github.qing.multtypeimagelayout.adapter; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.ImageView; 8 | import android.widget.TextView; 9 | 10 | import com.bumptech.glide.Glide; 11 | import com.github.qing.multtypeimagelayout.R; 12 | import com.github.qing.multtypeimagelayout.data.RecommendData; 13 | 14 | import java.util.List; 15 | 16 | import butterknife.BindView; 17 | import butterknife.ButterKnife; 18 | 19 | /** 20 | * Created by dcq on 2017/4/10. 21 | *

22 | * 推荐中的card 23 | */ 24 | 25 | public class RecommendCardAdapter extends RecyclerView.Adapter { 26 | 27 | List datas; 28 | 29 | public void setDatas(List datas) { 30 | this.datas = datas; 31 | } 32 | 33 | @Override 34 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 35 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recommend_card_layout, parent, false); 36 | return new ViewHolder(view); 37 | } 38 | 39 | @Override 40 | public void onBindViewHolder(ViewHolder holder, int position) { 41 | 42 | RecommendData data = datas.get(position); 43 | holder.recomTitle.setText(data.getTitle()); 44 | holder.recomWho.setText(data.getWhoRecom()); 45 | Glide.with(holder.itemView.getContext()) 46 | .load(data.getIcon()) 47 | .into(holder.recomImage); 48 | } 49 | 50 | @Override 51 | public int getItemCount() { 52 | return datas.size(); 53 | } 54 | 55 | static class ViewHolder extends RecyclerView.ViewHolder { 56 | 57 | @BindView(R.id.recomImage) 58 | ImageView recomImage; 59 | @BindView(R.id.recomTitle) 60 | TextView recomTitle; 61 | @BindView(R.id.recomWho) 62 | TextView recomWho; 63 | 64 | public ViewHolder(View itemView) { 65 | super(itemView); 66 | ButterKnife.bind(this, itemView); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/qing/multtypeimagelayout/data/ContentData.java: -------------------------------------------------------------------------------- 1 | package com.github.qing.multtypeimagelayout.data; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Random; 6 | 7 | public class ContentData { 8 | 9 | public static class Type { 10 | // 图片 11 | public static final int TYPE_IMG = 1; 12 | // 音乐 13 | public static final int TYPE_MUSIC = 2; 14 | // 视频 15 | public static final int TYPE_VIDEO = 3; 16 | } 17 | 18 | 19 | /** 20 | * icon : 图标 21 | * title : 标题 22 | * time : 时间 23 | * content : 文本内容 24 | * type : 1.图片、2.音频、3.视频 25 | * like : 收藏个数 26 | * comments : 评论个数 27 | * share : 分享信息 28 | * img : [{"url":"图片地址","width":"宽度","height":"高度"}] 29 | * video : {"videoImageUrl":"视频封面地址","videoUrl":"视频地址"} 30 | * music : {"mscIcon":"音乐封面","mscName":"音乐名称","mscSinger":"演唱者","mscUrl":"音乐获取地址"} 31 | */ 32 | 33 | private String icon; 34 | private String title; 35 | private String time; 36 | private String content; 37 | private int type; 38 | private int like; 39 | private int comments; 40 | private VideoBean video; 41 | private MusicBean music; 42 | private List img; 43 | private String newsUrl; 44 | 45 | public String getNewsUrl() { 46 | return newsUrl; 47 | } 48 | 49 | public void setNewsUrl(String newsUrl) { 50 | this.newsUrl = newsUrl; 51 | } 52 | 53 | public String getIcon() { 54 | return icon; 55 | } 56 | 57 | public void setIcon(String icon) { 58 | this.icon = icon; 59 | } 60 | 61 | public String getTitle() { 62 | return title; 63 | } 64 | 65 | public void setTitle(String title) { 66 | this.title = title; 67 | } 68 | 69 | public String getTime() { 70 | return time; 71 | } 72 | 73 | public void setTime(String time) { 74 | this.time = time; 75 | } 76 | 77 | public String getContent() { 78 | return content; 79 | } 80 | 81 | public void setContent(String content) { 82 | this.content = content; 83 | } 84 | 85 | public int getType() { 86 | return type; 87 | } 88 | 89 | public void setType(int type) { 90 | this.type = type; 91 | } 92 | 93 | public int getLike() { 94 | return like; 95 | } 96 | 97 | public void setLike(int like) { 98 | this.like = like; 99 | } 100 | 101 | public int getComments() { 102 | return comments; 103 | } 104 | 105 | public void setComments(int comments) { 106 | this.comments = comments; 107 | } 108 | 109 | public VideoBean getVideo() { 110 | return video; 111 | } 112 | 113 | public void setVideo(VideoBean video) { 114 | this.video = video; 115 | } 116 | 117 | public MusicBean getMusic() { 118 | return music; 119 | } 120 | 121 | public void setMusic(MusicBean music) { 122 | this.music = music; 123 | } 124 | 125 | public List getImg() { 126 | return img; 127 | } 128 | 129 | public void setImg(List img) { 130 | this.img = img; 131 | } 132 | 133 | 134 | public static class RandomData { 135 | private static Random random = new Random(); 136 | 137 | private static String[] titles = { 138 | "今天微博都在热议什么", 139 | "值得一看的长文章", 140 | "越狱第五季", 141 | "果壳精选", 142 | "睡前一张美女图", 143 | "知乎最新", 144 | "微博最热话题", 145 | "微信新动向", 146 | "Mac高效应用推荐", 147 | "每日冷笑话精选" 148 | }; 149 | 150 | private static String[] contents = { 151 | "iconmonstr网站收录了超过3600个图标,并对其进行了分类。每一个图标都提供了SVG, AI, PSD, PNG, FONT等格式", 152 | "Captain Icon收录了超过350个漂亮,漂亮,漂亮(重说三)的图标", 153 | "现在能有意外结局还让人颠覆的故事,真的很难得了。结局半小时的反转再反转,能自圆其说,能刷新认识,能大呼过瘾,对一部悬疑推理片来说已经完成的相当漂亮。不会苛求太多,这样的故事和设定已经满足。", 154 | "最近苏有朋导演的中国版《嫌疑人X的献身》正在上映,却不知这部原版有多经典。本片改编自日本人气推理小说家东野圭吾06年的直木奖获奖作品,福山雅治、柴崎幸、堤真一主演…逻辑和推理,终究敌不过对一个人的深爱。", 155 | "抱着对法庭题材的偏见去看,以为会很沉闷枯燥,没想到竟是一部够回味好几天的片子。不仅仅因为惊艳的结尾,整部戏就像让观者身临其境一样", 156 | "前面铺垫紧张到冒汗,倒数第10分钟,剧情反转", 157 | "原话剧精妙的剧本、对白、场景、悬念,甚至演员的演技,很好的通过电视电影的形式展现,并无限放大其精髓和魅力。", 158 | "自 iOS 7 以来,App 的图标愈发复杂而精致。尽管每个人都知道苹果注重细节,然而并不是每个人都能在这微小变化中发现其背后复杂的设计逻辑。", 159 | "我日常当然不会使用这台手机,所以只安装了几个优化APP以及谷歌框架,没有任何日常APP", 160 | "实验用APP名单:爱奇艺、百度贴吧、百度地图、滴滴出行、美团、去哪儿旅行、QQ、QQ音乐、手机京东、手机淘宝、腾讯新闻、UC浏览器、微博、微信、支付宝、百度手机助手", 161 | "《人民的名义》已经成为一部现象级作品,无论城市乡村,还是老少男女都看得过瘾,知识分子拍手叫好,投资方名利双收。", 162 | "“蓝瘦香菇”梗出来的时候,知乎上有个问题,大致是疑惑这种一点也不好笑的东西为什么一夜之间就火了。", 163 | "随着互联网这张饼越来越大,越来越多的资本发现它有利可图逐步介入。" 164 | }; 165 | 166 | private static String DEFAULT_URL = "http://mp.weixin.qq.com/s?__biz=MjM5MjAyNDUyMA==&mid=2650498255&idx=1&sn=b4fc8a6a8b16d63b35260b401dc8af29&chksm=bea3566889d4df7e3560fc1a74e5a608cf9ae38117445dfbaac01ef196c574028730688f922f&scene=4#wechat_redirect"; 167 | 168 | public static List random() { 169 | List datas = new ArrayList<>(); 170 | 171 | int count = random.nextInt(100); 172 | if (count < 20) { 173 | count = 20; 174 | } 175 | for (int i = 0; i < count; i++) { 176 | ContentData data = new ContentData(); 177 | data.setNewsUrl(DEFAULT_URL); 178 | data.setTitle(titles[random.nextInt(titles.length - 1)]); 179 | data.setIcon(ImageUrl.thumbUrl(ImageUrl.ICONS[random.nextInt(ImageUrl.ICONS.length - 1)])); 180 | data.setComments(random.nextInt(200)); 181 | data.setContent(contents[random.nextInt(contents.length - 1)]); 182 | data.setLike(random.nextInt(100)); 183 | data.setTime("10:23"); 184 | 185 | int type = random.nextInt(4); 186 | if (type == 0) { 187 | type = Type.TYPE_IMG; 188 | } 189 | data.setType(type); 190 | 191 | if (type == Type.TYPE_IMG) { 192 | data.setImg(ImgBean.RandomData.random()); 193 | } else if (type == Type.TYPE_MUSIC) { 194 | data.setMusic(MusicBean.RandomData.random()); 195 | } else if (type == Type.TYPE_VIDEO) { 196 | data.setVideo(VideoBean.RandomData.random()); 197 | } 198 | 199 | datas.add(data); 200 | } 201 | 202 | return datas; 203 | } 204 | } 205 | 206 | public static class VideoBean { 207 | /** 208 | * videoImageUrl : 视频封面地址 209 | * videoUrl : 视频地址 210 | */ 211 | 212 | private String videoImageUrl; 213 | private String videoUrl; 214 | 215 | public String getVideoImageUrl() { 216 | return videoImageUrl; 217 | } 218 | 219 | public void setVideoImageUrl(String videoImageUrl) { 220 | this.videoImageUrl = videoImageUrl; 221 | } 222 | 223 | public String getVideoUrl() { 224 | return videoUrl; 225 | } 226 | 227 | public void setVideoUrl(String videoUrl) { 228 | this.videoUrl = videoUrl; 229 | } 230 | 231 | public static class RandomData { 232 | private static Random random = new Random(); 233 | 234 | public static VideoBean random() { 235 | VideoBean videoBean = new VideoBean(); 236 | videoBean.setVideoImageUrl(ImageUrl.normalUrl(ImageUrl.URLS[random.nextInt(ImageUrl.URLS.length - 1)])); 237 | return videoBean; 238 | } 239 | } 240 | } 241 | 242 | public static class MusicBean { 243 | /** 244 | * mscIcon : 音乐封面 245 | * mscName : 音乐名称 246 | * mscSinger : 演唱者 247 | * mscUrl : 音乐获取地址 248 | */ 249 | 250 | private String mscIcon; 251 | private String mscName; 252 | private String mscSinger; 253 | private String mscUrl; 254 | 255 | public String getMscIcon() { 256 | return mscIcon; 257 | } 258 | 259 | public void setMscIcon(String mscIcon) { 260 | this.mscIcon = mscIcon; 261 | } 262 | 263 | public String getMscName() { 264 | return mscName; 265 | } 266 | 267 | public void setMscName(String mscName) { 268 | this.mscName = mscName; 269 | } 270 | 271 | public String getMscSinger() { 272 | return mscSinger; 273 | } 274 | 275 | public void setMscSinger(String mscSinger) { 276 | this.mscSinger = mscSinger; 277 | } 278 | 279 | public String getMscUrl() { 280 | return mscUrl; 281 | } 282 | 283 | public void setMscUrl(String mscUrl) { 284 | this.mscUrl = mscUrl; 285 | } 286 | 287 | public static class RandomData { 288 | private static Random random = new Random(); 289 | 290 | public static MusicBean random() { 291 | MusicBean musicBean = new MusicBean(); 292 | musicBean.setMscName("追梦人"); 293 | musicBean.setMscSinger("白若溪"); 294 | musicBean.setMscIcon(ImageUrl.thumbUrl(ImageUrl.URLS[random.nextInt(ImageUrl.URLS.length - 1)])); 295 | return musicBean; 296 | } 297 | } 298 | } 299 | 300 | public static class ImgBean { 301 | /** 302 | * url : 图片地址 303 | * width : 宽度 304 | * height : 高度 305 | */ 306 | 307 | private String url; 308 | private int width; 309 | private int height; 310 | 311 | public int getWidth() { 312 | return width; 313 | } 314 | 315 | public void setWidth(int width) { 316 | this.width = width; 317 | } 318 | 319 | public int getHeight() { 320 | return height; 321 | } 322 | 323 | public void setHeight(int height) { 324 | this.height = height; 325 | } 326 | 327 | public String getUrl() { 328 | return url; 329 | } 330 | 331 | public void setUrl(String url) { 332 | this.url = url; 333 | } 334 | 335 | 336 | public static class RandomData { 337 | private static Random random = new Random(); 338 | 339 | public static List random() { 340 | List datas = new ArrayList<>(); 341 | int count = random.nextInt(10); 342 | for (int i = 0; i < count; i++) { 343 | ImgBean imgBean = new ImgBean(); 344 | imgBean.setUrl(ImageUrl.URLS[random.nextInt(ImageUrl.URLS.length - 1)]); 345 | imgBean.setWidth(800); 346 | imgBean.setHeight(500); 347 | datas.add(imgBean); 348 | } 349 | 350 | return datas; 351 | } 352 | } 353 | } 354 | } 355 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/qing/multtypeimagelayout/data/DataFactory.java: -------------------------------------------------------------------------------- 1 | package com.github.qing.multtypeimagelayout.data; 2 | 3 | import com.github.qing.multtypeimagelayout.viewbinder.ContentDataType; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | public class DataFactory { 9 | 10 | public static List createData() { 11 | return flatTypeData(createMetaData()); 12 | } 13 | 14 | private static JikeData createMetaData() { 15 | JikeData jikeData = new JikeData(); 16 | 17 | jikeData.setHotData(HotData.RandomData.random()); 18 | jikeData.setContentDatas(ContentData.RandomData.random()); 19 | jikeData.setRecommendDatas(RecommendData.RandomData.random()); 20 | jikeData.setWeatherData(WeatherData.RandomData.random()); 21 | 22 | return jikeData; 23 | } 24 | 25 | private static List flatTypeData(JikeData data) { 26 | List items = new ArrayList<>(); 27 | items.add(data.getHotData()); 28 | List contentDatas = data.getContentDatas(); 29 | for (int i = 0; i < contentDatas.size(); i++) { 30 | ContentData item = contentDatas.get(i); 31 | 32 | // 根据ContentData的type确定构建那种类型的item 33 | int type = ContentDataType.TYPE_TEXT; 34 | if (item.getType() == ContentData.Type.TYPE_IMG) { 35 | if (item.getImg().size() == 0) { 36 | type = ContentDataType.TYPE_TEXT; 37 | } else if (item.getImg().size() == 1) { 38 | type = ContentDataType.TYPE_SINGLE_IMAGE; 39 | } else { 40 | type = ContentDataType.TYPE_MULTI_IMAGE; 41 | } 42 | } else if (item.getType() == ContentData.Type.TYPE_VIDEO) { 43 | type = ContentDataType.TYPE_VIDEO; 44 | } else if (item.getType() == ContentData.Type.TYPE_MUSIC) { 45 | type = ContentDataType.TYPE_MUSIC; 46 | } 47 | // 包装 ContentData 类型 --> ContentDataType 类型,用于1对多的Item映射 48 | items.add(new ContentDataType(item, type)); 49 | 50 | // 随便找了个位置,放置【天气item】和【推荐item】 51 | if (i == 5) { 52 | items.add(data.getWeatherData()); 53 | } 54 | if (i == 8) { 55 | items.add(new RecommendList(data.getRecommendDatas())); 56 | } 57 | } 58 | return items; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/qing/multtypeimagelayout/data/HotData.java: -------------------------------------------------------------------------------- 1 | package com.github.qing.multtypeimagelayout.data; 2 | 3 | import java.util.Random; 4 | 5 | public class HotData { 6 | 7 | private String content; 8 | private String source; 9 | private String icon; 10 | 11 | public String getContent() { 12 | return content; 13 | } 14 | 15 | public void setContent(String content) { 16 | this.content = content; 17 | } 18 | 19 | public String getSource() { 20 | return source; 21 | } 22 | 23 | public void setSource(String source) { 24 | this.source = source; 25 | } 26 | 27 | public String getIcon() { 28 | return icon; 29 | } 30 | 31 | public void setIcon(String icon) { 32 | this.icon = icon; 33 | } 34 | 35 | 36 | public static class RandomData { 37 | private static Random random = new Random(); 38 | 39 | private static String[] contents = { 40 | "你的室友能提供给你最大限度的安慰是「我也没开始做呢」。", 41 | "婚后发现妻子以前的经历十分复杂,该怎么相处?", 42 | "浅谈产品经理的8大核心工作" 43 | }; 44 | 45 | private static String[] sources = { 46 | "人人都是产品经理", 47 | "浴室沉思", 48 | "抽屉新热榜每日最热" 49 | }; 50 | 51 | private static String[] icons = { 52 | "http://onxvhxvw6.bkt.clouddn.com/image/jike/jike_1491801948230_pic.jpeg", 53 | "http://onxvhxvw6.bkt.clouddn.com/image/jike/jike_1491801956529_pic.jpeg", 54 | "http://onxvhxvw6.bkt.clouddn.com/image/jike/jike_1491801964316_pic.jpeg" 55 | }; 56 | 57 | 58 | public static HotData random() { 59 | HotData hotData = new HotData(); 60 | hotData.setContent(contents[random.nextInt(contents.length - 1)]); 61 | hotData.setIcon(icons[random.nextInt(icons.length - 1)]); 62 | hotData.setSource(sources[random.nextInt(sources.length - 1)]); 63 | return hotData; 64 | } 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/qing/multtypeimagelayout/data/ImageUrl.java: -------------------------------------------------------------------------------- 1 | package com.github.qing.multtypeimagelayout.data; 2 | 3 | public class ImageUrl { 4 | 5 | /** 6 | * 缩略图后缀 7 | */ 8 | private static String THUMB_SUFFIX = "?imageView2/1/w/200/h/200/format/webp/q/75|imageslim"; 9 | /** 10 | * 正常图片后缀 11 | */ 12 | private static String NORMAL_SUFFIX = "?imageView2/0/q/100|imageslim"; 13 | 14 | private static String WEBP_SUFFIX = "?imageView2/0/format/webp/q/1|imageslim"; 15 | 16 | public static String[] URLS = { 17 | "http://onxvhxvw6.bkt.clouddn.com/image/fengjing/01.jpg", 18 | "http://onxvhxvw6.bkt.clouddn.com/image/fengjing/05.jpg", 19 | "http://onxvhxvw6.bkt.clouddn.com/image/fengjing/12378628_1342603613473.jpg", 20 | "http://onxvhxvw6.bkt.clouddn.com/image/fengjing/12378628_1342603613475.jpg", 21 | "http://onxvhxvw6.bkt.clouddn.com/image/fengjing/13464336_1346396602086_800x600.jpg", 22 | "http://onxvhxvw6.bkt.clouddn.com/image/fengjing/1621215101-0.jpg", 23 | "http://onxvhxvw6.bkt.clouddn.com/image/fengjing/2010071529420095.jpg", 24 | "http://onxvhxvw6.bkt.clouddn.com/image/fengjing/23151400_1373424309126_800x600.jpg", 25 | "http://onxvhxvw6.bkt.clouddn.com/image/fengjing/3904.jpg", 26 | "http://onxvhxvw6.bkt.clouddn.com/image/fengjing/4U718R3B5607.jpg", 27 | "http://onxvhxvw6.bkt.clouddn.com/image/fengjing/500fd9f9d72a605911bbcd082b34349b033bba7c.jpg", 28 | "http://onxvhxvw6.bkt.clouddn.com/image/fengjing/52734bbec6cad.jpg", 29 | "http://onxvhxvw6.bkt.clouddn.com/image/fengjing/53df2e6510d13.jpg", 30 | "http://onxvhxvw6.bkt.clouddn.com/image/fengjing/5895522.jpg", 31 | }; 32 | 33 | public static String[] ICONS = { 34 | "http://onxvhxvw6.bkt.clouddn.com/image/icon/App_807px_1128336_easyicon.net.png", 35 | "http://onxvhxvw6.bkt.clouddn.com/image/icon/App_Store_114px_1076591_easyicon.net.png", 36 | "http://onxvhxvw6.bkt.clouddn.com/image/icon/Apple_App_Store_256px_1131811_easyicon.net.png", 37 | "http://onxvhxvw6.bkt.clouddn.com/image/icon/Bubbles_1024px_1184591_easyicon.net.png", 38 | "http://onxvhxvw6.bkt.clouddn.com/image/icon/Connected_1024px_1184588_easyicon.net.png", 39 | "http://onxvhxvw6.bkt.clouddn.com/image/icon/Crossed_1024px_1184587_easyicon.net.png", 40 | "http://onxvhxvw6.bkt.clouddn.com/image/icon/Disc_1024px_1184586_easyicon.net.png", 41 | "http://onxvhxvw6.bkt.clouddn.com/image/icon/Dots_1024px_1184584_easyicon.net%20%281%29.png", 42 | "http://onxvhxvw6.bkt.clouddn.com/image/icon/Festive_1024px_1184582_easyicon.net.png", 43 | "http://onxvhxvw6.bkt.clouddn.com/image/icon/Payments_1024px_1184574_easyicon.net.png", 44 | "http://onxvhxvw6.bkt.clouddn.com/image/icon/Pieces_1024px_1184573_easyicon.net.png", 45 | "http://onxvhxvw6.bkt.clouddn.com/image/icon/Stream_1024px_1184568_easyicon.net.png", 46 | "http://onxvhxvw6.bkt.clouddn.com/image/icon/Sun_1024px_1184567_easyicon.net.png", 47 | "http://onxvhxvw6.bkt.clouddn.com/image/icon/Ticks_1024px_1184566_easyicon.net.png", 48 | "http://onxvhxvw6.bkt.clouddn.com/image/icon/Weather_1024px_1184564_easyicon.net.png", 49 | "http://onxvhxvw6.bkt.clouddn.com/image/icon/aple_app_512px_1143679_easyicon.net.png", 50 | "http://onxvhxvw6.bkt.clouddn.com/image/icon/app_drawer_96px_1110305_easyicon.net.png", 51 | "http://onxvhxvw6.bkt.clouddn.com/image/icon/google_android_apps_reader_app_streamlistactivity_111px_1135342_easyicon.net.png", 52 | "http://onxvhxvw6.bkt.clouddn.com/image/icon/iCal_App_512px_561900_easyicon.net.png", 53 | }; 54 | 55 | public static String thumbUrl(String url) { 56 | return url + THUMB_SUFFIX; 57 | } 58 | 59 | public static String normalUrl(String url) { 60 | return url + NORMAL_SUFFIX; 61 | } 62 | 63 | public static String webplUrl(String url) { 64 | return url + WEBP_SUFFIX; 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/qing/multtypeimagelayout/data/JikeData.java: -------------------------------------------------------------------------------- 1 | package com.github.qing.multtypeimagelayout.data; 2 | 3 | 4 | import java.util.List; 5 | 6 | public class JikeData { 7 | 8 | private HotData hotData; 9 | private List recommendDatas; 10 | private WeatherData weatherData; 11 | private List contentDatas; 12 | 13 | public HotData getHotData() { 14 | return hotData; 15 | } 16 | 17 | public void setHotData(HotData hotData) { 18 | this.hotData = hotData; 19 | } 20 | 21 | public List getRecommendDatas() { 22 | return recommendDatas; 23 | } 24 | 25 | public void setRecommendDatas(List recommendDatas) { 26 | this.recommendDatas = recommendDatas; 27 | } 28 | 29 | public WeatherData getWeatherData() { 30 | return weatherData; 31 | } 32 | 33 | public void setWeatherData(WeatherData weatherData) { 34 | this.weatherData = weatherData; 35 | } 36 | 37 | public List getContentDatas() { 38 | return contentDatas; 39 | } 40 | 41 | public void setContentDatas(List contentDatas) { 42 | this.contentDatas = contentDatas; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/qing/multtypeimagelayout/data/RecommendData.java: -------------------------------------------------------------------------------- 1 | package com.github.qing.multtypeimagelayout.data; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Random; 6 | 7 | public class RecommendData { 8 | 9 | private String icon; 10 | private String title; 11 | private String whoRecom; 12 | 13 | public String getIcon() { 14 | return icon; 15 | } 16 | 17 | public void setIcon(String icon) { 18 | this.icon = icon; 19 | } 20 | 21 | public String getTitle() { 22 | return title; 23 | } 24 | 25 | public void setTitle(String title) { 26 | this.title = title; 27 | } 28 | 29 | public String getWhoRecom() { 30 | return whoRecom; 31 | } 32 | 33 | public void setWhoRecom(String whoRecom) { 34 | this.whoRecom = whoRecom; 35 | } 36 | 37 | public static class RandomData { 38 | private static Random random = new Random(); 39 | 40 | private static String[] titles = { 41 | "现在娱乐圈谁比较火", 42 | "电影新资讯", 43 | "Geek史上的今天", 44 | "ZARA折扣提醒", 45 | "微博热议", 46 | "知乎热门", 47 | "网易轻松一刻" 48 | }; 49 | 50 | private static String[] whoRecoms = { 51 | "编辑推荐", 52 | "有人刚刚关注", 53 | "大家都在看", 54 | "你可能感兴趣的", 55 | "近期新鲜推荐", 56 | "热门搜索", 57 | "大家力推", 58 | }; 59 | 60 | private static String THUMB_SUFFIX = "?imageView2/1/w/200/h/200/format/webp/q/75|imageslim"; 61 | 62 | public static List random() { 63 | List datas = new ArrayList<>(); 64 | int count = random.nextInt(20); 65 | if (count < 5) { 66 | count = 5; 67 | } 68 | for (int i = 0; i < count; i++) { 69 | int index = random.nextInt(titles.length - 1); 70 | RecommendData data = new RecommendData(); 71 | data.setTitle(titles[index]); 72 | data.setWhoRecom(whoRecoms[index]); 73 | data.setIcon(ImageUrl.ICONS[random.nextInt(ImageUrl.ICONS.length - 1)] + THUMB_SUFFIX); 74 | datas.add(data); 75 | } 76 | return datas; 77 | } 78 | 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/qing/multtypeimagelayout/data/RecommendList.java: -------------------------------------------------------------------------------- 1 | package com.github.qing.multtypeimagelayout.data; 2 | 3 | import java.util.List; 4 | 5 | public class RecommendList { 6 | 7 | List recommendDataList; 8 | 9 | public RecommendList(List recommendDataList) { 10 | this.recommendDataList = recommendDataList; 11 | } 12 | 13 | public List getRecommendDataList() { 14 | return recommendDataList; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/qing/multtypeimagelayout/data/WeatherData.java: -------------------------------------------------------------------------------- 1 | package com.github.qing.multtypeimagelayout.data; 2 | 3 | import com.github.qing.multtypeimagelayout.R; 4 | 5 | import java.util.Random; 6 | 7 | public class WeatherData { 8 | 9 | private String city; 10 | private String temper; 11 | private String type; 12 | private String quality; 13 | private int icon; 14 | 15 | public String getCity() { 16 | return city; 17 | } 18 | 19 | public void setCity(String city) { 20 | this.city = city; 21 | } 22 | 23 | public String getTemper() { 24 | return temper; 25 | } 26 | 27 | public void setTemper(String temper) { 28 | this.temper = temper; 29 | } 30 | 31 | public String getType() { 32 | return type; 33 | } 34 | 35 | public void setType(String type) { 36 | this.type = type; 37 | } 38 | 39 | public String getQuality() { 40 | return quality; 41 | } 42 | 43 | public void setQuality(String quality) { 44 | this.quality = quality; 45 | } 46 | 47 | public int getIcon() { 48 | return icon; 49 | } 50 | 51 | public void setIcon(int icon) { 52 | this.icon = icon; 53 | } 54 | 55 | public static class RandomData { 56 | 57 | private static Random random = new Random(); 58 | 59 | private static String[] citys = { 60 | "北京", 61 | "上海", 62 | "深圳", 63 | "杭州", 64 | "郑州" 65 | }; 66 | 67 | private static String[] qualitys = {"一般", "良好", "严重污染", "雾霾"}; 68 | 69 | private static String[] types = {"晴天", "多云", "阴天", "小雨", "中雨"}; 70 | 71 | private static String[] tempers = {"10~14℃", "10~24℃", "4~10℃", "5~12℃", "12~14℃"}; 72 | 73 | private static int[] icons = { 74 | R.mipmap.weather01, 75 | R.mipmap.weather03, 76 | R.mipmap.weather05 77 | }; 78 | 79 | public static WeatherData random() { 80 | WeatherData data = new WeatherData(); 81 | data.setCity(citys[random.nextInt(citys.length - 1)]); 82 | data.setIcon(icons[random.nextInt(icons.length - 1)]); 83 | data.setType(types[random.nextInt(types.length - 1)]); 84 | data.setQuality(qualitys[random.nextInt(qualitys.length - 1)]); 85 | data.setTemper(tempers[random.nextInt(tempers.length - 1)]); 86 | return data; 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/qing/multtypeimagelayout/manager/ImgGridLayoutManager.java: -------------------------------------------------------------------------------- 1 | package com.github.qing.multtypeimagelayout.manager; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.GridLayoutManager; 5 | import android.util.AttributeSet; 6 | 7 | /** 8 | * Created by dcq on 2017/4/10. 9 | *

10 | * 九宫格布局Manager 11 | */ 12 | 13 | public class ImgGridLayoutManager extends GridLayoutManager { 14 | 15 | public static final int SPAN_SIZE = 6; 16 | private int totalSize = 0; 17 | 18 | public ImgGridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 19 | super(context, attrs, defStyleAttr, defStyleRes); 20 | init(); 21 | } 22 | 23 | public ImgGridLayoutManager(Context context) { 24 | super(context, SPAN_SIZE); 25 | init(); 26 | } 27 | 28 | public ImgGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) { 29 | super(context, spanCount, orientation, reverseLayout); 30 | init(); 31 | } 32 | 33 | private void init() { 34 | /** 35 | * 此处使用Grid每个item占几个Span来实现九宫格的效果, 36 | * 默认每行6个item,实际最多显示3张图片,所以常规情况下,每张图片占据2个item的span 37 | */ 38 | setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { 39 | @Override 40 | public int getSpanSize(int position) { 41 | int total = getTotalSize(); 42 | // 当只有一张图片时,直接占据整行 43 | if (total == 1) { 44 | return SPAN_SIZE; 45 | } 46 | // 当只有2张时,应该每张占据3个span,当只有3张时,应该每张占据2个span 47 | else if (total == 2 || total == 3) { 48 | return SPAN_SIZE / total; 49 | } 50 | // 当有4张或7张时,第一张会占据整行,其余的每个item占2个span 51 | else if (total == 4 || total == 7) { 52 | if (position == 0) { 53 | return SPAN_SIZE; 54 | } else { 55 | return SPAN_SIZE / 3; 56 | } 57 | } 58 | // 当5张或8张时,前两张图片会均分整行,也就是每个占据3个span,其余的3张占据一行,所以每个占2个span 59 | else if (total == 5 || total == 8) { 60 | if (position == 0 || position == 1) { 61 | return SPAN_SIZE / 2; 62 | } else { 63 | return SPAN_SIZE / 3; 64 | } 65 | } 66 | // 其余情况,也就是6和9,他们刚好每行都可以占据3张图片,且每张占据2个span 67 | else { 68 | return SPAN_SIZE / 3; 69 | } 70 | } 71 | }); 72 | } 73 | 74 | 75 | public void setTotalSize(int totalSize) { 76 | this.totalSize = totalSize; 77 | } 78 | 79 | public int getTotalSize() { 80 | return totalSize; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/qing/multtypeimagelayout/photo/LazyFragment.java: -------------------------------------------------------------------------------- 1 | package com.github.qing.multtypeimagelayout.photo; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v4.app.Fragment; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | 10 | /** 11 | * Created by dcq on 2017/4/12. 12 | *

13 | * 懒加载的Fragment 14 | */ 15 | 16 | public abstract class LazyFragment extends Fragment { 17 | 18 | private boolean isPrepared; 19 | /** 20 | * 是否第一次加载 21 | */ 22 | private boolean isFirstLoad = true; 23 | private boolean isFragmentVisible; 24 | 25 | @Nullable 26 | @Override 27 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 28 | isFirstLoad = true; 29 | View view = initViews(inflater, container, savedInstanceState); 30 | isPrepared = true; 31 | lazyLoad(); 32 | return view; 33 | } 34 | 35 | protected abstract View initViews(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState); 36 | 37 | protected abstract void onLazy(); 38 | 39 | @Override 40 | public void setUserVisibleHint(boolean isVisibleToUser) { 41 | super.setUserVisibleHint(isVisibleToUser); 42 | if (getUserVisibleHint()) { 43 | onVisible(); 44 | } else { 45 | onInvisible(); 46 | } 47 | } 48 | 49 | @Override 50 | public void onHiddenChanged(boolean hidden) { 51 | super.onHiddenChanged(hidden); 52 | if (!hidden) { 53 | onVisible(); 54 | } else { 55 | onInvisible(); 56 | } 57 | } 58 | 59 | protected void onVisible() { 60 | isFragmentVisible = true; 61 | lazyLoad(); 62 | } 63 | 64 | protected void onInvisible() { 65 | isFragmentVisible = false; 66 | } 67 | 68 | 69 | protected void lazyLoad() { 70 | if (isPrepared && isFragmentVisible) { 71 | if (isFirstLoad) { 72 | isFirstLoad = false; 73 | onLazy(); 74 | } 75 | } 76 | } 77 | 78 | 79 | @Override 80 | public void onDestroyView() { 81 | super.onDestroyView(); 82 | isPrepared = false; 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/qing/multtypeimagelayout/photo/PhotoActivity.java: -------------------------------------------------------------------------------- 1 | package com.github.qing.multtypeimagelayout.photo; 2 | 3 | import android.content.Intent; 4 | import android.graphics.Color; 5 | import android.graphics.Rect; 6 | import android.os.Bundle; 7 | import android.support.v4.app.Fragment; 8 | import android.support.v4.app.FragmentActivity; 9 | import android.support.v4.app.FragmentManager; 10 | import android.support.v4.app.FragmentPagerAdapter; 11 | import android.support.v4.view.ViewPager; 12 | import android.view.KeyEvent; 13 | import android.view.View; 14 | import android.view.ViewTreeObserver; 15 | import android.widget.TextView; 16 | 17 | import com.github.qing.multtypeimagelayout.R; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | 22 | import butterknife.BindView; 23 | import butterknife.ButterKnife; 24 | 25 | public class PhotoActivity extends FragmentActivity { 26 | 27 | public static final String KEY_IMG_URL = "img_url"; 28 | public static final String KEY_RECT = "rect"; 29 | public static final String KEY_INDEX = "index"; 30 | 31 | @BindView(R.id.viewPager) 32 | PhotoViewPager viewPager; 33 | @BindView(R.id.indicator) 34 | TextView indicator; 35 | 36 | private ArrayList rects; 37 | private int currentIndex; 38 | 39 | private List fragments = new ArrayList<>(); 40 | 41 | @Override 42 | protected void onCreate(Bundle savedInstanceState) { 43 | super.onCreate(savedInstanceState); 44 | setContentView(R.layout.activity_photo); 45 | ButterKnife.bind(this); 46 | 47 | initArgs(); 48 | initViewPager(); 49 | 50 | } 51 | 52 | private void initArgs() { 53 | Intent intent = getIntent(); 54 | String[] imgUrls = intent.getStringArrayExtra(KEY_IMG_URL); 55 | rects = intent.getParcelableArrayListExtra(KEY_RECT); 56 | currentIndex = intent.getIntExtra(KEY_INDEX, 0); 57 | 58 | if (imgUrls != null && rects != null && imgUrls.length == rects.size()) { 59 | for (int i = 0; i < imgUrls.length; i++) { 60 | PhotoFragment fragment = new PhotoFragment(); 61 | Bundle bundle = new Bundle(); 62 | bundle.putString(PhotoFragment.KEY_IMG_URL, imgUrls[i]); 63 | bundle.putParcelable(PhotoFragment.KEY_START_BOUND, rects.get(i)); 64 | bundle.putBoolean(PhotoFragment.KEY_TRANS_PHOTO, currentIndex == i); 65 | fragment.setArguments(bundle); 66 | fragments.add(fragment); 67 | } 68 | } else { 69 | finish(); 70 | } 71 | } 72 | 73 | private void initViewPager() { 74 | PhotoPagerAdapter adapter = new PhotoPagerAdapter(getSupportFragmentManager()); 75 | viewPager.setAdapter(adapter); 76 | viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { 77 | @Override 78 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 79 | 80 | } 81 | 82 | @Override 83 | public void onPageSelected(int position) { 84 | indicator.setText((position + 1) + " / " + fragments.size()); 85 | } 86 | 87 | @Override 88 | public void onPageScrollStateChanged(int state) { 89 | 90 | } 91 | }); 92 | viewPager.setCurrentItem(currentIndex); 93 | 94 | 95 | viewPager.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { 96 | @Override 97 | public void onGlobalLayout() { 98 | viewPager.getViewTreeObserver().removeGlobalOnLayoutListener(this); 99 | final PhotoFragment fragment = fragments.get(currentIndex); 100 | fragment.transformIn(); 101 | indicator.setText((currentIndex + 1) + " / " + fragments.size()); 102 | 103 | } 104 | }); 105 | 106 | if (fragments.size() == 1) { 107 | indicator.setVisibility(View.GONE); 108 | } 109 | } 110 | 111 | private boolean isTransformOut = false; 112 | 113 | public void transformOut() { 114 | if (isTransformOut) { 115 | return; 116 | } 117 | isTransformOut = true; 118 | int currentItem = viewPager.getCurrentItem(); 119 | if (currentItem < rects.size()) { 120 | PhotoFragment fragment = fragments.get(currentItem); 121 | indicator.setVisibility(View.GONE); 122 | fragment.changeBg(Color.TRANSPARENT); 123 | fragment.transformOut(new SmoothImageView.onTransformListener() { 124 | @Override 125 | public void onTransformCompleted(SmoothImageView.Status status) { 126 | exit(); 127 | } 128 | }); 129 | } else { 130 | exit(); 131 | } 132 | } 133 | 134 | private void exit() { 135 | finish(); 136 | overridePendingTransition(0, 0); 137 | } 138 | 139 | @Override 140 | public boolean onKeyDown(int keyCode, KeyEvent event) { 141 | if (keyCode == KeyEvent.KEYCODE_BACK) { 142 | transformOut(); 143 | return true; 144 | } 145 | return super.onKeyDown(keyCode, event); 146 | } 147 | 148 | private class PhotoPagerAdapter extends FragmentPagerAdapter { 149 | 150 | PhotoPagerAdapter(FragmentManager fm) { 151 | super(fm); 152 | } 153 | 154 | @Override 155 | public Fragment getItem(int position) { 156 | return fragments.get(position); 157 | } 158 | 159 | @Override 160 | public int getCount() { 161 | return fragments.size(); 162 | } 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/qing/multtypeimagelayout/photo/PhotoFragment.java: -------------------------------------------------------------------------------- 1 | package com.github.qing.multtypeimagelayout.photo; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.Color; 5 | import android.graphics.Rect; 6 | import android.graphics.drawable.Drawable; 7 | import android.os.Bundle; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.ImageView; 12 | 13 | import com.bumptech.glide.Glide; 14 | import com.bumptech.glide.request.animation.GlideAnimation; 15 | import com.bumptech.glide.request.target.SimpleTarget; 16 | import com.github.chrisbanes.photoview.OnPhotoTapListener; 17 | import com.github.qing.multtypeimagelayout.R; 18 | import com.github.qing.multtypeimagelayout.data.ImageUrl; 19 | 20 | import butterknife.BindView; 21 | import butterknife.ButterKnife; 22 | 23 | /** 24 | * Created by dcq on 2017/4/12. 25 | *

26 | * 使用PhotoView显示单张图片的Fragment 27 | */ 28 | 29 | public class PhotoFragment extends LazyFragment { 30 | 31 | public static final String KEY_IMG_URL = "img_url"; 32 | public static final String KEY_START_BOUND = "startBounds"; 33 | public static final String KEY_TRANS_PHOTO = "is_trans_photo"; 34 | 35 | 36 | @BindView(R.id.photoView) 37 | SmoothImageView photoView; 38 | @BindView(R.id.rootView) 39 | View rootView; 40 | @BindView(R.id.progressContainer) 41 | View progress; 42 | 43 | private String imgUrl; 44 | // 是否是以动画进入的Fragment 45 | private boolean isTransPhoto = false; 46 | 47 | @Override 48 | protected View initViews(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 49 | View view = inflater.inflate(R.layout.fragment_photo_layout, container, false); 50 | ButterKnife.bind(this, view); 51 | 52 | initArgs(); 53 | initView(); 54 | 55 | return view; 56 | } 57 | 58 | 59 | private void initArgs() { 60 | Bundle args = getArguments(); 61 | if (args != null && args.containsKey(KEY_IMG_URL)) { 62 | imgUrl = args.getString(KEY_IMG_URL); 63 | Rect startBounds = args.getParcelable(KEY_START_BOUND); 64 | photoView.setThumbRect(startBounds); 65 | isTransPhoto = args.getBoolean(KEY_TRANS_PHOTO, false); 66 | 67 | // 先加在小图中Glide已经缓存过的图片,在Fragment显示的时,再加载清晰的大图 68 | Glide.with(this).load(ImageUrl.webplUrl(imgUrl)).asBitmap().into(new SimpleTarget() { 69 | @Override 70 | public void onResourceReady(Bitmap resource, GlideAnimation glideAnimation) { 71 | if (photoView.getDrawable() == null) { 72 | photoView.setImageBitmap(resource); 73 | } 74 | } 75 | }); 76 | } 77 | } 78 | 79 | private void initView() { 80 | // 非动画进入的Fragment,默认背景为黑色 81 | if (!isTransPhoto) { 82 | rootView.setBackgroundColor(Color.BLACK); 83 | } 84 | photoView.setMinimumScale(1f); 85 | photoView.setOnPhotoTapListener(new OnPhotoTapListener() { 86 | @Override 87 | public void onPhotoTap(ImageView view, float x, float y) { 88 | if (photoView.checkMinScale()) { 89 | ((PhotoActivity) getActivity()).transformOut(); 90 | } 91 | } 92 | }); 93 | 94 | photoView.setAlphaChangeListener(new SmoothImageView.OnAlphaChangeListener() { 95 | @Override 96 | public void onAlphaChange(int alpha) { 97 | rootView.setBackgroundColor(getColorWithAlpha(alpha / 255f, Color.BLACK)); 98 | } 99 | }); 100 | 101 | photoView.setTransformOutListener(new SmoothImageView.OnTransformOutListener() { 102 | @Override 103 | public void onTransformOut() { 104 | if (photoView.checkMinScale()) { 105 | ((PhotoActivity) getActivity()).transformOut(); 106 | } 107 | } 108 | }); 109 | } 110 | 111 | public static int getColorWithAlpha(float alpha, int baseColor) { 112 | int a = Math.min(255, Math.max(0, (int) (alpha * 255))) << 24; 113 | int rgb = 0x00ffffff & baseColor; 114 | return a + rgb; 115 | } 116 | 117 | private boolean isLoaded = false; 118 | private boolean isLoadFinish = false; 119 | 120 | @Override 121 | protected void onLazy() { 122 | if (isLoaded) { 123 | return; 124 | } 125 | isLoaded = true; 126 | Glide.with(this).load(imgUrl).asBitmap().into(new SimpleTarget() { 127 | 128 | @Override 129 | public void onLoadStarted(Drawable placeholder) { 130 | progress.postDelayed(new Runnable() { 131 | @Override 132 | public void run() { 133 | if (!isLoadFinish) { 134 | progress.setVisibility(View.VISIBLE); 135 | } 136 | } 137 | }, 400); 138 | } 139 | 140 | @Override 141 | public void onLoadFailed(Exception e, Drawable errorDrawable) { 142 | progress.setVisibility(View.GONE); 143 | } 144 | 145 | @Override 146 | public void onResourceReady(Bitmap bitmap, GlideAnimation glideAnimation) { 147 | isLoadFinish = true; 148 | progress.setVisibility(View.GONE); 149 | photoView.setImageBitmap(bitmap); 150 | } 151 | }); 152 | } 153 | 154 | public void transformIn() { 155 | photoView.transformIn(new SmoothImageView.onTransformListener() { 156 | @Override 157 | public void onTransformCompleted(SmoothImageView.Status status) { 158 | rootView.setBackgroundColor(Color.BLACK); 159 | } 160 | }); 161 | } 162 | 163 | public void transformOut(SmoothImageView.onTransformListener listener) { 164 | photoView.transformOut(listener); 165 | } 166 | 167 | public void changeBg(int color) { 168 | rootView.setBackgroundColor(color); 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/qing/multtypeimagelayout/photo/PhotoViewPager.java: -------------------------------------------------------------------------------- 1 | package com.github.qing.multtypeimagelayout.photo; 2 | 3 | import android.content.Context; 4 | import android.support.v4.view.ViewPager; 5 | import android.util.AttributeSet; 6 | import android.view.MotionEvent; 7 | 8 | /** 9 | * Created by dcq on 2017/4/12. 10 | *

11 | * https://github.com/chrisbanes/PhotoView 12 | * Issues With ViewGroups 13 | */ 14 | 15 | public class PhotoViewPager extends ViewPager { 16 | public PhotoViewPager(Context context) { 17 | super(context); 18 | } 19 | 20 | public PhotoViewPager(Context context, AttributeSet attrs) { 21 | super(context, attrs); 22 | } 23 | 24 | @Override 25 | public boolean onInterceptTouchEvent(MotionEvent ev) { 26 | try { 27 | return super.onInterceptTouchEvent(ev); 28 | } catch (IllegalArgumentException e) { 29 | e.printStackTrace(); 30 | return false; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/qing/multtypeimagelayout/photo/SmoothImageView.java: -------------------------------------------------------------------------------- 1 | package com.github.qing.multtypeimagelayout.photo; 2 | 3 | import android.animation.Animator; 4 | import android.animation.AnimatorListenerAdapter; 5 | import android.animation.AnimatorSet; 6 | import android.animation.PropertyValuesHolder; 7 | import android.animation.ValueAnimator; 8 | import android.content.Context; 9 | import android.graphics.Bitmap; 10 | import android.graphics.Canvas; 11 | import android.graphics.Matrix; 12 | import android.graphics.Paint; 13 | import android.graphics.Rect; 14 | import android.graphics.drawable.BitmapDrawable; 15 | import android.util.AttributeSet; 16 | import android.view.MotionEvent; 17 | import android.view.animation.AccelerateDecelerateInterpolator; 18 | 19 | import com.github.chrisbanes.photoview.PhotoView; 20 | import com.github.qing.multtypeimagelayout.R; 21 | 22 | import java.lang.reflect.Field; 23 | 24 | 25 | public class SmoothImageView extends PhotoView { 26 | 27 | enum Status { 28 | STATE_NORMAL, 29 | STATE_IN, 30 | STATE_OUT, 31 | STATE_MOVE 32 | } 33 | 34 | private Status mStatus = Status.STATE_NORMAL; 35 | private static final int TRANSFORM_DURATION = 300; 36 | private Paint mPaint; 37 | private Matrix matrix; 38 | private Bitmap mBitmap; 39 | 40 | private Transform startTransform; 41 | private Transform endTransform; 42 | private Transform animTransform; 43 | private Rect thumbRect; 44 | private boolean transformStart; 45 | 46 | private class Transform implements Cloneable { 47 | float left, top, width, height; 48 | int alpha; 49 | float scale; 50 | 51 | public Transform clone() { 52 | Transform obj = null; 53 | try { 54 | obj = (Transform) super.clone(); 55 | } catch (CloneNotSupportedException e) { 56 | e.printStackTrace(); 57 | } 58 | return obj; 59 | } 60 | } 61 | 62 | public SmoothImageView(Context context, AttributeSet attrs) { 63 | super(context, attrs); 64 | initSmoothImageView(); 65 | } 66 | 67 | public SmoothImageView(Context context) { 68 | super(context); 69 | initSmoothImageView(); 70 | } 71 | 72 | private void initSmoothImageView() { 73 | mPaint = new Paint(); 74 | mPaint.setStyle(Paint.Style.FILL); 75 | mPaint.setColor(0xFF000000); 76 | matrix = new Matrix(); 77 | setScaleType(ScaleType.FIT_CENTER); 78 | } 79 | 80 | public boolean checkMinScale() { 81 | if (getScale() != 1) { 82 | setScale(1, true); 83 | return false; 84 | } 85 | return true; 86 | } 87 | 88 | @Override 89 | protected void onDraw(Canvas canvas) { 90 | if (getDrawable() == null) { 91 | return; 92 | } 93 | 94 | if (mStatus == Status.STATE_OUT || mStatus == Status.STATE_IN) { 95 | if (startTransform == null || endTransform == null || animTransform == null) { 96 | initTransform(); 97 | } 98 | 99 | if (animTransform == null) { 100 | super.onDraw(canvas); 101 | return; 102 | } 103 | 104 | mPaint.setAlpha(animTransform.alpha); 105 | canvas.drawPaint(mPaint); 106 | int saveCount = canvas.getSaveCount(); 107 | matrix.setScale(animTransform.scale, animTransform.scale); 108 | float translateX = -(mBitmap.getWidth() * animTransform.scale - animTransform.width) / 2; 109 | float translateY = -(mBitmap.getHeight() * animTransform.scale - animTransform.height) / 2; 110 | matrix.postTranslate(translateX, translateY); 111 | 112 | canvas.translate(animTransform.left, animTransform.top); 113 | canvas.clipRect(0, 0, animTransform.width, animTransform.height); 114 | canvas.concat(matrix); 115 | getDrawable().draw(canvas); 116 | canvas.restoreToCount(saveCount); 117 | 118 | if (transformStart) { 119 | startTransform(); 120 | } 121 | } else if (mStatus == Status.STATE_MOVE) { 122 | mPaint.setAlpha(0); 123 | canvas.drawPaint(mPaint); 124 | super.onDraw(canvas); 125 | } else { 126 | mPaint.setAlpha(255); 127 | canvas.drawPaint(mPaint); 128 | super.onDraw(canvas); 129 | } 130 | } 131 | 132 | private int downX, downY; 133 | private boolean isMoved = false; 134 | private boolean isDownPhoto = false; 135 | private int alpha = 0; 136 | private static final int MIN_TRANS_DEST = 5; 137 | private static final float MAX_TRANS_SCALE = 0.5f; 138 | 139 | 140 | @Override 141 | public boolean dispatchTouchEvent(MotionEvent event) { 142 | if (getScale() == 1) { 143 | int action = event.getAction(); 144 | switch (action) { 145 | case MotionEvent.ACTION_DOWN: 146 | downX = (int) event.getX(); 147 | downY = (int) event.getY(); 148 | if (markTransform == null) { 149 | initTransform(); 150 | } 151 | isDownPhoto = false; 152 | if (markTransform != null) { 153 | int startY = (int) markTransform.top; 154 | int endY = (int) (markTransform.height + markTransform.top); 155 | if (downY >= startY && endY >= downY) { 156 | isDownPhoto = true; 157 | } 158 | } 159 | 160 | isMoved = false; 161 | break; 162 | case MotionEvent.ACTION_MOVE: 163 | if (!isDownPhoto) { 164 | break; 165 | } 166 | 167 | int mx = (int) event.getX(); 168 | int my = (int) event.getY(); 169 | 170 | int offsetX = mx - downX; 171 | int offsetY = my - downY; 172 | 173 | // 水平方向移动不予处理 174 | if (!isMoved && (Math.abs(offsetX) > Math.abs(offsetY) || Math.abs(offsetY) < MIN_TRANS_DEST)) { 175 | return super.dispatchTouchEvent(event); 176 | } else { 177 | // 一指滑动时,才对图片进行移动缩放处理 178 | if (event.getPointerCount() == 1) { 179 | mStatus = Status.STATE_MOVE; 180 | offsetLeftAndRight(offsetX); 181 | offsetTopAndBottom(offsetY); 182 | float scale = moveScale(); 183 | float scaleXY = 1 - scale * 0.1f; 184 | setScaleY(scaleXY); 185 | setScaleX(scaleXY); 186 | isMoved = true; 187 | alpha = (int) (255 * (1 - scale * 0.5f)); 188 | invalidate(); 189 | if (alpha < 0) { 190 | alpha = 0; 191 | } 192 | if (alphaChangeListener != null) { 193 | alphaChangeListener.onAlphaChange(alpha); 194 | } 195 | return true; 196 | } 197 | // 多指滑动,直接屏蔽事件 198 | else { 199 | return true; 200 | } 201 | } 202 | case MotionEvent.ACTION_UP: 203 | case MotionEvent.ACTION_CANCEL: 204 | if (isMoved) { 205 | if (moveScale() <= MAX_TRANS_SCALE) { 206 | moveToOldPosition(); 207 | } else { 208 | changeTransform(); 209 | if (transformOutListener != null) { 210 | transformOutListener.onTransformOut(); 211 | } 212 | } 213 | return true; 214 | } 215 | break; 216 | } 217 | } 218 | return super.dispatchTouchEvent(event); 219 | } 220 | 221 | /** 222 | * 未达到关闭的阈值松手时,返回到初始位置 223 | */ 224 | private void moveToOldPosition() { 225 | ValueAnimator va = ValueAnimator.ofInt(getTop(), 0); 226 | va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 227 | int startValue = 0; 228 | 229 | @Override 230 | public void onAnimationUpdate(ValueAnimator animation) { 231 | int value = (int) animation.getAnimatedValue(); 232 | if (startValue != 0) { 233 | offsetTopAndBottom(value - startValue); 234 | } 235 | startValue = value; 236 | } 237 | }); 238 | 239 | ValueAnimator leftAnim = ValueAnimator.ofInt(getLeft(), 0); 240 | leftAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 241 | int startValue = 0; 242 | 243 | @Override 244 | public void onAnimationUpdate(ValueAnimator animation) { 245 | int value = (int) animation.getAnimatedValue(); 246 | if (startValue != 0) { 247 | offsetLeftAndRight(value - startValue); 248 | } 249 | startValue = value; 250 | } 251 | }); 252 | 253 | ValueAnimator alphaAnim = ValueAnimator.ofInt(alpha, 255); 254 | alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 255 | @Override 256 | public void onAnimationUpdate(ValueAnimator animation) { 257 | if (alphaChangeListener != null) { 258 | alphaChangeListener.onAlphaChange((Integer) animation.getAnimatedValue()); 259 | } 260 | } 261 | }); 262 | 263 | ValueAnimator scaleAnim = ValueAnimator.ofFloat(getScaleX(), 1); 264 | scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 265 | @Override 266 | public void onAnimationUpdate(ValueAnimator animation) { 267 | float scale = (float) animation.getAnimatedValue(); 268 | setScaleX(scale); 269 | setScaleY(scale); 270 | } 271 | }); 272 | 273 | AnimatorSet as = new AnimatorSet(); 274 | as.setDuration(TRANSFORM_DURATION); 275 | as.setInterpolator(new AccelerateDecelerateInterpolator()); 276 | as.playTogether(va, leftAnim, scaleAnim, alphaAnim); 277 | as.start(); 278 | } 279 | 280 | private float moveScale() { 281 | if (markTransform == null) { 282 | initTransform(); 283 | } 284 | return Math.abs(getTop() / markTransform.height); 285 | } 286 | 287 | private OnAlphaChangeListener alphaChangeListener; 288 | private OnTransformOutListener transformOutListener; 289 | 290 | 291 | public void setTransformOutListener(OnTransformOutListener transformOutListener) { 292 | this.transformOutListener = transformOutListener; 293 | } 294 | 295 | public void setAlphaChangeListener(OnAlphaChangeListener alphaChangeListener) { 296 | this.alphaChangeListener = alphaChangeListener; 297 | } 298 | 299 | public interface OnTransformOutListener { 300 | void onTransformOut(); 301 | } 302 | 303 | public interface OnAlphaChangeListener { 304 | void onAlphaChange(int alpha); 305 | } 306 | 307 | private Transform markTransform; 308 | 309 | private void changeTransform() { 310 | if (markTransform != null) { 311 | Transform tempTransform = markTransform.clone(); 312 | tempTransform.top = markTransform.top + getTop(); 313 | tempTransform.left = markTransform.left + getLeft(); 314 | tempTransform.alpha = alpha; 315 | tempTransform.scale = markTransform.scale - (1 - getScaleX()) * markTransform.scale; 316 | animTransform = tempTransform.clone(); 317 | endTransform = tempTransform.clone(); 318 | } 319 | } 320 | 321 | private void startTransform() { 322 | transformStart = false; 323 | if (animTransform == null) { 324 | return; 325 | } 326 | 327 | ValueAnimator animator = new ValueAnimator(); 328 | animator.setDuration(TRANSFORM_DURATION); 329 | animator.setInterpolator(new AccelerateDecelerateInterpolator()); 330 | if (mStatus == Status.STATE_IN) { 331 | PropertyValuesHolder scaleHolder = PropertyValuesHolder.ofFloat("animScale", startTransform.scale, endTransform.scale); 332 | PropertyValuesHolder alphaHolder = PropertyValuesHolder.ofInt("animAlpha", startTransform.alpha, endTransform.alpha); 333 | PropertyValuesHolder leftHolder = PropertyValuesHolder.ofFloat("animLeft", startTransform.left, endTransform.left); 334 | PropertyValuesHolder topHolder = PropertyValuesHolder.ofFloat("animTop", startTransform.top, endTransform.top); 335 | PropertyValuesHolder widthHolder = PropertyValuesHolder.ofFloat("animWidth", startTransform.width, endTransform.width); 336 | PropertyValuesHolder heightHolder = PropertyValuesHolder.ofFloat("animHeight", startTransform.height, endTransform.height); 337 | animator.setValues(scaleHolder, alphaHolder, leftHolder, topHolder, widthHolder, heightHolder); 338 | } else if (mStatus == Status.STATE_OUT) { 339 | PropertyValuesHolder scaleHolder = PropertyValuesHolder.ofFloat("animScale", endTransform.scale, startTransform.scale); 340 | PropertyValuesHolder alphaHolder = PropertyValuesHolder.ofInt("animAlpha", endTransform.alpha, startTransform.alpha); 341 | PropertyValuesHolder leftHolder = PropertyValuesHolder.ofFloat("animLeft", endTransform.left, startTransform.left); 342 | PropertyValuesHolder topHolder = PropertyValuesHolder.ofFloat("animTop", endTransform.top, startTransform.top); 343 | PropertyValuesHolder widthHolder = PropertyValuesHolder.ofFloat("animWidth", endTransform.width, startTransform.width); 344 | PropertyValuesHolder heightHolder = PropertyValuesHolder.ofFloat("animHeight", endTransform.height, startTransform.height); 345 | animator.setValues(scaleHolder, alphaHolder, leftHolder, topHolder, widthHolder, heightHolder); 346 | } 347 | animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 348 | @Override 349 | public void onAnimationUpdate(ValueAnimator animation) { 350 | animTransform.alpha = (Integer) animation.getAnimatedValue("animAlpha"); 351 | animTransform.scale = (float) animation.getAnimatedValue("animScale"); 352 | animTransform.left = (float) animation.getAnimatedValue("animLeft"); 353 | animTransform.top = (float) animation.getAnimatedValue("animTop"); 354 | animTransform.width = (float) animation.getAnimatedValue("animWidth"); 355 | animTransform.height = (float) animation.getAnimatedValue("animHeight"); 356 | invalidate(); 357 | } 358 | }); 359 | animator.addListener(new AnimatorListenerAdapter() { 360 | @Override 361 | public void onAnimationEnd(Animator animation) { 362 | /* 363 | * 如果是进入的话,当然是希望最后停留在center_crop的区域。但是如果是out的话,就不应该是center_crop的位置了 364 | * , 而应该是最后变化的位置,因为当out的时候结束时,不回复视图是Normal,要不然会有一个突然闪动回去的bug 365 | */ 366 | if (onTransformListener != null) { 367 | onTransformListener.onTransformCompleted(mStatus); 368 | } 369 | if (mStatus == Status.STATE_IN) { 370 | mStatus = Status.STATE_NORMAL; 371 | } 372 | } 373 | }); 374 | animator.start(); 375 | 376 | } 377 | 378 | public void transformIn(onTransformListener listener) { 379 | setOnTransformListener(listener); 380 | transformStart = true; 381 | mStatus = Status.STATE_IN; 382 | invalidate(); 383 | } 384 | 385 | public void transformOut(onTransformListener listener) { 386 | if (getTop() != 0) { 387 | offsetTopAndBottom(-getTop()); 388 | } 389 | if (getLeft() != 0) { 390 | offsetLeftAndRight(-getLeft()); 391 | } 392 | if (getScaleX() != 1) { 393 | setScaleX(1); 394 | setScaleY(1); 395 | } 396 | setOnTransformListener(listener); 397 | transformStart = true; 398 | mStatus = Status.STATE_OUT; 399 | invalidate(); 400 | } 401 | 402 | /** 403 | * 设置起始位置图片的Rect 404 | * 405 | * @param thumbRect 406 | */ 407 | public void setThumbRect(Rect thumbRect) { 408 | this.thumbRect = thumbRect; 409 | } 410 | 411 | private void initTransform() { 412 | if (getDrawable() == null) { 413 | return; 414 | } 415 | if (startTransform != null && endTransform != null && animTransform != null) { 416 | return; 417 | } 418 | if (getWidth() == 0 || getHeight() == 0) { 419 | return; 420 | } 421 | if (mBitmap == null) { 422 | mBitmap = ((BitmapDrawable) getDrawable()).getBitmap(); 423 | } 424 | 425 | startTransform = new Transform(); 426 | startTransform.alpha = 0; 427 | startTransform.left = thumbRect.left; 428 | startTransform.top = thumbRect.top - getStatusBarHeight(getContext()); 429 | startTransform.width = thumbRect.width(); 430 | startTransform.height = thumbRect.height(); 431 | 432 | int bitmapWidth = mBitmap.getWidth(); 433 | int bitmapHeight = mBitmap.getHeight(); 434 | 435 | //开始时以CenterCrop方式显示,缩放图片使图片的一边等于起始区域的一边,另一边大于起始区域 436 | float startScaleX = (float) thumbRect.width() / bitmapWidth; 437 | float startScaleY = (float) thumbRect.height() / bitmapHeight; 438 | startTransform.scale = startScaleX > startScaleY ? startScaleX : startScaleY; 439 | //结束时以fitCenter方式显示,缩放图片使图片的一边等于View的一边,另一边大于View 440 | float endScaleX = (float) getWidth() / bitmapWidth; 441 | float endScaleY = (float) getHeight() / bitmapHeight; 442 | 443 | endTransform = new Transform(); 444 | endTransform.scale = endScaleX < endScaleY ? endScaleX : endScaleY; 445 | endTransform.alpha = 255; 446 | int endBitmapWidth = (int) (endTransform.scale * bitmapWidth); 447 | int endBitmapHeight = (int) (endTransform.scale * bitmapHeight); 448 | endTransform.left = (getWidth() - endBitmapWidth) / 2; 449 | endTransform.top = (getHeight() - endBitmapHeight) / 2; 450 | endTransform.width = endBitmapWidth; 451 | endTransform.height = endBitmapHeight; 452 | 453 | if (mStatus == Status.STATE_IN) { 454 | animTransform = startTransform.clone(); 455 | } else if (mStatus == Status.STATE_OUT) { 456 | animTransform = endTransform.clone(); 457 | } 458 | 459 | markTransform = endTransform; 460 | } 461 | 462 | public interface onTransformListener { 463 | void onTransformCompleted(Status status); 464 | 465 | } 466 | 467 | private onTransformListener onTransformListener; 468 | 469 | 470 | public void setOnTransformListener(SmoothImageView.onTransformListener onTransformListener) { 471 | this.onTransformListener = onTransformListener; 472 | } 473 | 474 | public static int getStatusBarHeight(Context context) { 475 | int statusBarHeight = context.getResources().getDimensionPixelSize(R.dimen.default_status_bar_height); 476 | try { 477 | Class c = Class.forName("com.android.internal.R$dimen"); 478 | Object obj = c.newInstance(); 479 | Field field = c.getField("status_bar_height"); 480 | int x = Integer.parseInt(field.get(obj).toString()); 481 | statusBarHeight = context.getResources().getDimensionPixelSize(x); 482 | return statusBarHeight; 483 | } catch (Exception e) { 484 | e.printStackTrace(); 485 | } 486 | return statusBarHeight; 487 | } 488 | 489 | 490 | } 491 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/qing/multtypeimagelayout/utils/DisplayUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.qing.multtypeimagelayout.utils; 2 | 3 | import android.content.Context; 4 | import android.graphics.Point; 5 | import android.util.DisplayMetrics; 6 | 7 | public class DisplayUtils { 8 | 9 | /** 10 | * 获取屏幕尺寸 11 | * 12 | * @param context 13 | * @return 14 | */ 15 | public static Point getScreenWH(Context context) { 16 | Point point = new Point(); 17 | 18 | DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); 19 | point.set(displayMetrics.widthPixels, displayMetrics.heightPixels); 20 | 21 | return point; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/qing/multtypeimagelayout/utils/ImageLoader.java: -------------------------------------------------------------------------------- 1 | package com.github.qing.multtypeimagelayout.utils; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.graphics.drawable.ColorDrawable; 6 | import android.widget.ImageView; 7 | 8 | import com.bumptech.glide.Glide; 9 | import com.bumptech.glide.load.Transformation; 10 | 11 | /** 12 | * Created by dcq on 2017/4/10. 13 | *

14 | * 图片加载 15 | */ 16 | 17 | public class ImageLoader { 18 | 19 | 20 | public static void loadImage(Context context, String url, ImageView imageView) { 21 | Glide.with(context) 22 | .load(url) 23 | .asBitmap() 24 | .placeholder(new ColorDrawable(Color.parseColor("#eeeeee"))) 25 | .into(imageView); 26 | } 27 | 28 | public static void loadImage(Context context, String url, ImageView imageView, Transformation transformation) { 29 | Glide.with(context) 30 | .load(url) 31 | .placeholder(new ColorDrawable(Color.parseColor("#eeeeee"))) 32 | .bitmapTransform(transformation) 33 | .into(imageView); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/qing/multtypeimagelayout/viewbinder/BaseContentViewBinder.java: -------------------------------------------------------------------------------- 1 | package com.github.qing.multtypeimagelayout.viewbinder; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.support.annotation.NonNull; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.FrameLayout; 12 | import android.widget.ImageView; 13 | import android.widget.TextView; 14 | import android.widget.Toast; 15 | 16 | import com.bumptech.glide.Glide; 17 | import com.github.qing.multtypeimagelayout.NewsActivity; 18 | import com.github.qing.multtypeimagelayout.R; 19 | import com.github.qing.multtypeimagelayout.data.ContentData; 20 | 21 | import butterknife.BindView; 22 | import butterknife.ButterKnife; 23 | import me.drakeet.multitype.ItemViewBinder; 24 | 25 | /** 26 | * Created by dcq on 2017/4/10. 27 | *

28 | * 抽取公用的内容Item,包含头部标题,icon以及底部收藏、分享等,具体不同类型的内容,再通过一个ViewHolder去create和bind 29 | */ 30 | 31 | @SuppressWarnings("unchecked") 32 | public abstract class BaseContentViewBinder 33 | extends ItemViewBinder { 34 | 35 | /** 36 | * 定义item中不同内容的ViewHolder的创建 37 | * 38 | * @param inflater 39 | * @param parent R.id.contentFrame对应的FrameLayout 40 | * @return 41 | */ 42 | protected abstract SubViewHolder onCreateContentViewHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent); 43 | 44 | /** 45 | * 绑定内容布局中的数据 46 | * 47 | * @param holder 内容对应的ViewHolder 48 | * @param content 具体item的数据 49 | */ 50 | protected abstract void onBindContentViewHolder(SubViewHolder holder, @NonNull ContentData content); 51 | 52 | @NonNull 53 | @Override 54 | protected FrameHolder onCreateViewHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { 55 | View root = inflater.inflate(R.layout.item_base_content_layout, parent, false); 56 | FrameLayout contentFrame = (FrameLayout) root.findViewById(R.id.contentFrame); 57 | // 在此创建子内容ViewHolder,并设置给父容器的ViewHolder 58 | SubViewHolder subViewHolder = onCreateContentViewHolder(inflater, contentFrame); 59 | return new FrameHolder<>(root, subViewHolder); 60 | } 61 | 62 | 63 | @SuppressLint("SetTextI18n") 64 | @Override 65 | protected void onBindViewHolder(@NonNull FrameHolder holder, @NonNull ContentDataType dataType) { 66 | 67 | final ContentData item = dataType.getContentData(); 68 | 69 | holder.contentTitle.setText(item.getTitle()); 70 | holder.contentLike.setText("" + item.getLike()); 71 | holder.contentMsg.setText("" + item.getComments()); 72 | holder.contentTime.setText(item.getTime()); 73 | holder.content.setText(item.getContent()); 74 | 75 | Glide.with(holder.itemView.getContext()) 76 | .load(item.getIcon()) 77 | .into(holder.contentIcon); 78 | 79 | // 获取包含的子内容ViewHolder,根据是否设置了ViewHolder,来决定是否显示内容区域 80 | RecyclerView.ViewHolder subViewHolder = holder.subViewHolder; 81 | if (subViewHolder != null) { 82 | holder.contentFrame.setVisibility(View.VISIBLE); 83 | // 回调内容ViewHolder的数据绑定过程 84 | onBindContentViewHolder((SubViewHolder) subViewHolder, item); 85 | } else { 86 | holder.contentFrame.setVisibility(View.GONE); 87 | onBindContentViewHolder(null, item); 88 | } 89 | 90 | if (item.getType() == ContentData.Type.TYPE_IMG) { 91 | holder.typeImg.setImageResource(R.mipmap.link); 92 | } else if (item.getType() == ContentData.Type.TYPE_MUSIC) { 93 | holder.typeImg.setImageResource(R.mipmap.music); 94 | } else if (item.getType() == ContentData.Type.TYPE_VIDEO) { 95 | holder.typeImg.setImageResource(R.mipmap.play_gray); 96 | } 97 | 98 | final Context context = holder.itemView.getContext(); 99 | 100 | // 点击收藏 101 | holder.ivHeart.setOnClickListener(new View.OnClickListener() { 102 | @Override 103 | public void onClick(View v) { 104 | Toast.makeText(context, "收藏", Toast.LENGTH_SHORT).show(); 105 | } 106 | }); 107 | // 发表评论 108 | holder.ivMsg.setOnClickListener(new View.OnClickListener() { 109 | @Override 110 | public void onClick(View v) { 111 | Toast.makeText(context, "发表评论", Toast.LENGTH_SHORT).show(); 112 | } 113 | }); 114 | // 分享 115 | holder.ivShare.setOnClickListener(new View.OnClickListener() { 116 | @Override 117 | public void onClick(View v) { 118 | Toast.makeText(context, "分享", Toast.LENGTH_SHORT).show(); 119 | } 120 | }); 121 | 122 | // item 点击跳转 123 | holder.itemView.setOnClickListener(new View.OnClickListener() { 124 | @Override 125 | public void onClick(View v) { 126 | Intent intent = new Intent(context, NewsActivity.class); 127 | intent.putExtra(NewsActivity.KEY_TITLE, item.getTitle()); 128 | intent.putExtra(NewsActivity.KEY_URL, item.getNewsUrl()); 129 | context.startActivity(intent); 130 | } 131 | }); 132 | } 133 | 134 | class FrameHolder extends RecyclerView.ViewHolder { 135 | 136 | // 内容对应的ViewHolder 137 | SVH subViewHolder; 138 | 139 | @BindView(R.id.contentIcon) 140 | ImageView contentIcon; 141 | @BindView(R.id.contentTitle) 142 | TextView contentTitle; 143 | @BindView(R.id.contentTime) 144 | TextView contentTime; 145 | @BindView(R.id.content) 146 | TextView content; 147 | @BindView(R.id.contentFrame) 148 | FrameLayout contentFrame; 149 | @BindView(R.id.contentLike) 150 | TextView contentLike; 151 | @BindView(R.id.contentMsg) 152 | TextView contentMsg; 153 | @BindView(R.id.typeImg) 154 | ImageView typeImg; 155 | @BindView(R.id.ivHeart) 156 | ImageView ivHeart; 157 | @BindView(R.id.ivMsg) 158 | ImageView ivMsg; 159 | @BindView(R.id.ivShare) 160 | ImageView ivShare; 161 | 162 | 163 | FrameHolder(View itemView, SVH subViewHolder) { 164 | super(itemView); 165 | ButterKnife.bind(this, itemView); 166 | this.subViewHolder = subViewHolder; 167 | } 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/qing/multtypeimagelayout/viewbinder/ContentDataType.java: -------------------------------------------------------------------------------- 1 | package com.github.qing.multtypeimagelayout.viewbinder; 2 | 3 | import android.support.annotation.Nullable; 4 | 5 | import com.github.qing.multtypeimagelayout.data.ContentData; 6 | 7 | /** 8 | * Created by dcq on 2017/4/10. 9 | *

10 | * 类型转换 11 | */ 12 | 13 | public class ContentDataType { 14 | 15 | // 纯文本类型 16 | public static final int TYPE_TEXT = 1; 17 | // 单张图片类型 18 | public static final int TYPE_SINGLE_IMAGE = 2; 19 | // 多图类型 20 | public static final int TYPE_MULTI_IMAGE = 3; 21 | // 视频 22 | public static final int TYPE_VIDEO = 4; 23 | // 音频 24 | public static final int TYPE_MUSIC = 5; 25 | 26 | public abstract static class Text { 27 | } 28 | 29 | public abstract static class SingleImage { 30 | } 31 | 32 | public abstract static class MultiImage { 33 | } 34 | 35 | public abstract static class Video { 36 | } 37 | 38 | public abstract static class Music { 39 | } 40 | 41 | private ContentData contentData; 42 | private Class typeClass; 43 | 44 | public ContentDataType(ContentData contentData, int type) { 45 | this.contentData = contentData; 46 | this.typeClass = getTypeClass(type); 47 | } 48 | 49 | public ContentData getContentData() { 50 | return contentData; 51 | } 52 | 53 | public Class getTypeClass() { 54 | return typeClass; 55 | } 56 | 57 | @Nullable 58 | private static Class getTypeClass(int type) { 59 | switch (type) { 60 | case TYPE_TEXT: 61 | return Text.class; 62 | case TYPE_SINGLE_IMAGE: 63 | return SingleImage.class; 64 | case TYPE_MULTI_IMAGE: 65 | return MultiImage.class; 66 | case TYPE_VIDEO: 67 | return Video.class; 68 | case TYPE_MUSIC: 69 | return Music.class; 70 | } 71 | return null; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/qing/multtypeimagelayout/viewbinder/HotViewBinder.java: -------------------------------------------------------------------------------- 1 | package com.github.qing.multtypeimagelayout.viewbinder; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | import android.widget.TextView; 10 | 11 | import com.github.qing.multtypeimagelayout.R; 12 | import com.github.qing.multtypeimagelayout.data.HotData; 13 | import com.github.qing.multtypeimagelayout.utils.ImageLoader; 14 | 15 | import butterknife.BindView; 16 | import butterknife.ButterKnife; 17 | import me.drakeet.multitype.ItemViewBinder; 18 | 19 | /** 20 | * Created by dcq on 2017/4/10. 21 | *

22 | * 最近热门item 23 | */ 24 | 25 | public class HotViewBinder extends ItemViewBinder { 26 | 27 | @NonNull 28 | @Override 29 | protected ViewHolder onCreateViewHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { 30 | View view = inflater.inflate(R.layout.item_hot_layout, parent, false); 31 | return new ViewHolder(view); 32 | } 33 | 34 | @Override 35 | protected void onBindViewHolder(@NonNull ViewHolder holder, @NonNull HotData item) { 36 | 37 | holder.content.setText(item.getContent()); 38 | holder.hotSource.setText("来源:" + item.getSource()); 39 | ImageLoader.loadImage(holder.itemView.getContext(), item.getIcon(), holder.hotImage); 40 | } 41 | 42 | static class ViewHolder extends RecyclerView.ViewHolder { 43 | @BindView(R.id.content) 44 | TextView content; 45 | @BindView(R.id.hotImage) 46 | ImageView hotImage; 47 | @BindView(R.id.hotSource) 48 | TextView hotSource; 49 | 50 | ViewHolder(View itemView) { 51 | super(itemView); 52 | ButterKnife.bind(this, itemView); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/qing/multtypeimagelayout/viewbinder/MultiImgViewBinder.java: -------------------------------------------------------------------------------- 1 | package com.github.qing.multtypeimagelayout.viewbinder; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.graphics.Bitmap; 6 | import android.graphics.Rect; 7 | import android.support.annotation.NonNull; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | 13 | import com.github.qing.multtypeimagelayout.R; 14 | import com.github.qing.multtypeimagelayout.adapter.MultiImgAdapter; 15 | import com.github.qing.multtypeimagelayout.data.ContentData; 16 | import com.github.qing.multtypeimagelayout.manager.ImgGridLayoutManager; 17 | import com.github.qing.multtypeimagelayout.photo.PhotoActivity; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | 22 | import butterknife.BindView; 23 | import butterknife.ButterKnife; 24 | 25 | /** 26 | * Created by dcq on 2017/4/10. 27 | *

28 | * 多图item 29 | */ 30 | 31 | public class MultiImgViewBinder extends BaseContentViewBinder { 32 | 33 | @Override 34 | protected ViewHolder onCreateContentViewHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { 35 | return new ViewHolder(inflater.inflate(R.layout.item_mult_img_layout, parent, true)); 36 | } 37 | 38 | @Override 39 | protected void onBindContentViewHolder(ViewHolder holder, @NonNull ContentData content) { 40 | holder.setData(content.getImg()); 41 | } 42 | 43 | static class ViewHolder extends RecyclerView.ViewHolder { 44 | @BindView(R.id.multImgRecyclerView) 45 | RecyclerView multiImgRecyclerView; 46 | MultiImgAdapter adapter; 47 | ImgGridLayoutManager layoutManager; 48 | 49 | public ViewHolder(View itemView) { 50 | super(itemView); 51 | ButterKnife.bind(this, itemView); 52 | initRecycler(); 53 | } 54 | 55 | private void initRecycler() { 56 | layoutManager = new ImgGridLayoutManager(itemView.getContext()); 57 | multiImgRecyclerView.setLayoutManager(layoutManager); 58 | adapter = new MultiImgAdapter(multiImgRecyclerView); 59 | multiImgRecyclerView.setAdapter(adapter); 60 | } 61 | 62 | 63 | private void setData(final List list) { 64 | layoutManager.setTotalSize(list.size()); 65 | adapter.setData(list); 66 | multiImgRecyclerView.post(new Runnable() { 67 | @Override 68 | public void run() { 69 | adapter.notifyDataSetChanged(); 70 | } 71 | }); 72 | adapter.setListener(new MultiImgAdapter.OnImageClickListener() { 73 | @Override 74 | public void onImageClick(int position) { 75 | showPhoto(list, position); 76 | } 77 | }); 78 | } 79 | 80 | private void showPhoto(List list, int index) { 81 | String[] urls = new String[list.size()]; 82 | for (int i = 0; i < list.size(); i++) { 83 | urls[i] = list.get(i).getUrl(); 84 | } 85 | int childCount = multiImgRecyclerView.getChildCount(); 86 | ArrayList rects = new ArrayList<>(); 87 | for (int i = 0; i < childCount; i++) { 88 | View view = multiImgRecyclerView.getLayoutManager().findViewByPosition(i); 89 | Rect rect = new Rect(); 90 | view.getGlobalVisibleRect(rect); 91 | rects.add(rect); 92 | } 93 | 94 | Context context = itemView.getContext(); 95 | Intent intent = new Intent(context, PhotoActivity.class); 96 | intent.putExtra(PhotoActivity.KEY_INDEX, index); 97 | intent.putExtra(PhotoActivity.KEY_IMG_URL, urls); 98 | intent.putExtra(PhotoActivity.KEY_RECT, rects); 99 | context.startActivity(intent); 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/qing/multtypeimagelayout/viewbinder/MusicViewBinder.java: -------------------------------------------------------------------------------- 1 | package com.github.qing.multtypeimagelayout.viewbinder; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | import android.widget.TextView; 10 | import android.widget.Toast; 11 | 12 | import com.github.qing.multtypeimagelayout.R; 13 | import com.github.qing.multtypeimagelayout.data.ContentData; 14 | import com.github.qing.multtypeimagelayout.utils.ImageLoader; 15 | 16 | import butterknife.BindView; 17 | import butterknife.ButterKnife; 18 | import jp.wasabeef.glide.transformations.RoundedCornersTransformation; 19 | 20 | /** 21 | * Created by dcq on 2017/4/11. 22 | *

23 | * 音乐item 24 | */ 25 | 26 | public class MusicViewBinder extends BaseContentViewBinder { 27 | 28 | 29 | @Override 30 | protected ViewHolder onCreateContentViewHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { 31 | return new ViewHolder(inflater.inflate(R.layout.item_music_layout, parent, true)); 32 | } 33 | 34 | @Override 35 | protected void onBindContentViewHolder(ViewHolder holder, @NonNull ContentData content) { 36 | ContentData.MusicBean music = content.getMusic(); 37 | holder.musicName.setText(music.getMscName()); 38 | holder.musicSinger.setText(music.getMscSinger()); 39 | 40 | ImageLoader.loadImage(holder.itemView.getContext(), music.getMscIcon(), holder.musicIcon, 41 | new RoundedCornersTransformation(holder.itemView.getContext(), 10, 0)); 42 | } 43 | 44 | static class ViewHolder extends RecyclerView.ViewHolder { 45 | 46 | @BindView(R.id.musicIcon) 47 | ImageView musicIcon; 48 | @BindView(R.id.musicName) 49 | TextView musicName; 50 | @BindView(R.id.musicSinger) 51 | TextView musicSinger; 52 | 53 | public ViewHolder(final View itemView) { 54 | super(itemView); 55 | ButterKnife.bind(this, itemView); 56 | itemView.setOnClickListener(new View.OnClickListener() { 57 | @Override 58 | public void onClick(View v) { 59 | Toast.makeText(itemView.getContext(), "播放音乐", Toast.LENGTH_SHORT).show(); 60 | } 61 | }); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/qing/multtypeimagelayout/viewbinder/RecommendViewBinder.java: -------------------------------------------------------------------------------- 1 | package com.github.qing.multtypeimagelayout.viewbinder; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.support.v7.widget.LinearLayoutManager; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | 10 | import com.github.qing.itemdecoration.LinearSpaceItemDecoration; 11 | import com.github.qing.multtypeimagelayout.R; 12 | import com.github.qing.multtypeimagelayout.adapter.RecommendCardAdapter; 13 | import com.github.qing.multtypeimagelayout.data.RecommendData; 14 | import com.github.qing.multtypeimagelayout.data.RecommendList; 15 | 16 | import java.util.List; 17 | 18 | import butterknife.BindView; 19 | import butterknife.ButterKnife; 20 | import me.drakeet.multitype.ItemViewBinder; 21 | 22 | /** 23 | * Created by dcq on 2017/4/10. 24 | *

25 | * 推荐item 26 | */ 27 | 28 | public class RecommendViewBinder extends ItemViewBinder { 29 | 30 | @NonNull 31 | @Override 32 | protected ViewHolder onCreateViewHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { 33 | return new ViewHolder(inflater.inflate(R.layout.item_recommend_layout, parent, false)); 34 | } 35 | 36 | @Override 37 | protected void onBindViewHolder(@NonNull ViewHolder holder, @NonNull RecommendList item) { 38 | if (!holder.isInit) { 39 | holder.initRecyclerView(); 40 | } 41 | holder.setData(item.getRecommendDataList()); 42 | } 43 | 44 | static class ViewHolder extends RecyclerView.ViewHolder { 45 | 46 | @BindView(R.id.recommendRecyclerView) 47 | RecyclerView recommendRecyclerView; 48 | RecommendCardAdapter adapter; 49 | boolean isInit = false; 50 | 51 | ViewHolder(View itemView) { 52 | super(itemView); 53 | 54 | ButterKnife.bind(this, itemView); 55 | initRecyclerView(); 56 | } 57 | 58 | private void initRecyclerView() { 59 | isInit = true; 60 | adapter = new RecommendCardAdapter(); 61 | LinearLayoutManager layoutManager = new LinearLayoutManager(itemView.getContext(), LinearLayoutManager.HORIZONTAL, false); 62 | recommendRecyclerView.setLayoutManager(layoutManager); 63 | recommendRecyclerView.setAdapter(adapter); 64 | recommendRecyclerView.addItemDecoration( 65 | new LinearSpaceItemDecoration.Builder() 66 | .setOrientation(LinearLayoutManager.HORIZONTAL) 67 | .setSpaceSize(12) 68 | .build() 69 | ); 70 | } 71 | 72 | private void setData(List list) { 73 | if (adapter != null) { 74 | adapter.setDatas(list); 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/qing/multtypeimagelayout/viewbinder/SingleImgViewBinder.java: -------------------------------------------------------------------------------- 1 | package com.github.qing.multtypeimagelayout.viewbinder; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.graphics.Color; 6 | import android.graphics.Rect; 7 | import android.graphics.drawable.ColorDrawable; 8 | import android.support.annotation.NonNull; 9 | import android.support.v7.widget.RecyclerView; 10 | import android.view.LayoutInflater; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | import android.widget.ImageView; 14 | 15 | import com.bumptech.glide.Glide; 16 | import com.github.qing.multtypeimagelayout.R; 17 | import com.github.qing.multtypeimagelayout.data.ContentData; 18 | import com.github.qing.multtypeimagelayout.data.ImageUrl; 19 | import com.github.qing.multtypeimagelayout.photo.PhotoActivity; 20 | 21 | import java.util.ArrayList; 22 | 23 | import butterknife.BindView; 24 | import butterknife.ButterKnife; 25 | 26 | /** 27 | * Created by dcq on 2017/4/10. 28 | *

29 | * 单张图片item 30 | */ 31 | 32 | public class SingleImgViewBinder extends BaseContentViewBinder { 33 | 34 | 35 | @Override 36 | protected SingleImgViewHolder onCreateContentViewHolder(@NonNull LayoutInflater inflater, 37 | @NonNull ViewGroup parent) { 38 | View view = inflater.inflate(R.layout.item_content_single_image, parent, true); 39 | return new SingleImgViewHolder(view); 40 | } 41 | 42 | @Override 43 | protected void onBindContentViewHolder(@NonNull final SingleImgViewHolder holder, @NonNull ContentData content) { 44 | final ContentData.ImgBean imgBean = content.getImg().get(0); 45 | Glide.with(holder.itemView.getContext()) 46 | .load(ImageUrl.webplUrl(imgBean.getUrl())) 47 | .placeholder(new ColorDrawable(Color.parseColor("#eeeeee"))) 48 | .override(imgBean.getWidth(), imgBean.getHeight()) 49 | .into(holder.singleImg); 50 | holder.itemView.setOnClickListener(new View.OnClickListener() { 51 | @Override 52 | public void onClick(View v) { 53 | showPhoto(holder.singleImg, imgBean.getUrl()); 54 | } 55 | }); 56 | } 57 | 58 | private void showPhoto(ImageView imageView, String url) { 59 | String[] urls = {url}; 60 | ArrayList rects = new ArrayList<>(); 61 | Rect rect = new Rect(); 62 | imageView.getGlobalVisibleRect(rect); 63 | rects.add(rect); 64 | 65 | Context context = imageView.getContext(); 66 | Intent intent = new Intent(context, PhotoActivity.class); 67 | intent.putExtra(PhotoActivity.KEY_INDEX, 0); 68 | intent.putExtra(PhotoActivity.KEY_IMG_URL, urls); 69 | intent.putExtra(PhotoActivity.KEY_RECT, rects); 70 | context.startActivity(intent); 71 | } 72 | 73 | static class SingleImgViewHolder extends RecyclerView.ViewHolder { 74 | 75 | @BindView(R.id.singleImage) 76 | ImageView singleImg; 77 | 78 | SingleImgViewHolder(View itemView) { 79 | super(itemView); 80 | ButterKnife.bind(this, itemView); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/qing/multtypeimagelayout/viewbinder/TextContentViewBInder.java: -------------------------------------------------------------------------------- 1 | package com.github.qing.multtypeimagelayout.viewbinder; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.LayoutInflater; 6 | import android.view.ViewGroup; 7 | 8 | import com.github.qing.multtypeimagelayout.data.ContentData; 9 | 10 | /** 11 | * Created by dcq on 2017/4/10. 12 | *

13 | * 纯文本item 14 | */ 15 | 16 | public class TextContentViewBInder extends BaseContentViewBinder { 17 | 18 | @Override 19 | protected RecyclerView.ViewHolder onCreateContentViewHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { 20 | return null; 21 | } 22 | 23 | @Override 24 | protected void onBindContentViewHolder(@NonNull RecyclerView.ViewHolder holder, @NonNull ContentData content) { 25 | 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/qing/multtypeimagelayout/viewbinder/VideoViewBinder.java: -------------------------------------------------------------------------------- 1 | package com.github.qing.multtypeimagelayout.viewbinder; 2 | 3 | import android.graphics.Color; 4 | import android.support.annotation.NonNull; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.ImageView; 10 | import android.widget.Toast; 11 | 12 | import com.github.qing.multtypeimagelayout.R; 13 | import com.github.qing.multtypeimagelayout.data.ContentData; 14 | import com.github.qing.multtypeimagelayout.utils.ImageLoader; 15 | 16 | import butterknife.BindView; 17 | import butterknife.ButterKnife; 18 | import jp.wasabeef.glide.transformations.ColorFilterTransformation; 19 | 20 | /** 21 | * Created by dcq on 2017/4/11. 22 | *

23 | * 视频类型item 24 | */ 25 | 26 | public class VideoViewBinder extends BaseContentViewBinder { 27 | 28 | 29 | @Override 30 | protected ViewHolder onCreateContentViewHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { 31 | return new ViewHolder(inflater.inflate(R.layout.item_video_layout, parent, true)); 32 | } 33 | 34 | @Override 35 | protected void onBindContentViewHolder(ViewHolder holder, @NonNull ContentData content) { 36 | ContentData.VideoBean video = content.getVideo(); 37 | ImageLoader.loadImage(holder.itemView.getContext(), video.getVideoImageUrl(), holder.videoImg, 38 | new ColorFilterTransformation(holder.itemView.getContext(), Color.parseColor("#66000000"))); 39 | } 40 | 41 | static class ViewHolder extends RecyclerView.ViewHolder { 42 | 43 | @BindView(R.id.videoImg) 44 | ImageView videoImg; 45 | 46 | public ViewHolder(final View itemView) { 47 | super(itemView); 48 | ButterKnife.bind(this, itemView); 49 | 50 | itemView.setOnClickListener(new View.OnClickListener() { 51 | @Override 52 | public void onClick(View v) { 53 | Toast.makeText(itemView.getContext(), "播放视频", Toast.LENGTH_SHORT).show(); 54 | } 55 | }); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /app/src/main/java/com/github/qing/multtypeimagelayout/viewbinder/WeatherViewBinder.java: -------------------------------------------------------------------------------- 1 | package com.github.qing.multtypeimagelayout.viewbinder; 2 | 3 | import android.support.annotation.NonNull; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | import android.widget.TextView; 10 | 11 | import com.github.qing.multtypeimagelayout.R; 12 | import com.github.qing.multtypeimagelayout.data.WeatherData; 13 | 14 | import butterknife.BindView; 15 | import butterknife.ButterKnife; 16 | import me.drakeet.multitype.ItemViewBinder; 17 | 18 | /** 19 | * Created by dcq on 2017/4/10. 20 | *

21 | * 天气item 22 | */ 23 | 24 | public class WeatherViewBinder extends ItemViewBinder { 25 | 26 | @NonNull 27 | @Override 28 | protected ViewHolder onCreateViewHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { 29 | return new ViewHolder(inflater.inflate(R.layout.item_weather_layout, parent, false)); 30 | } 31 | 32 | @Override 33 | protected void onBindViewHolder(@NonNull ViewHolder holder, @NonNull WeatherData item) { 34 | 35 | holder.city.setText(item.getCity()); 36 | holder.temper.setText(item.getTemper() + " " + item.getType()); 37 | holder.weatherIcon.setImageResource(item.getIcon()); 38 | holder.weatherQuality.setText("空气质量:" + item.getQuality()); 39 | 40 | } 41 | 42 | static class ViewHolder extends RecyclerView.ViewHolder { 43 | 44 | @BindView(R.id.weatherQuality) 45 | TextView weatherQuality; 46 | @BindView(R.id.temper) 47 | TextView temper; 48 | @BindView(R.id.city) 49 | TextView city; 50 | @BindView(R.id.weatherIcon) 51 | ImageView weatherIcon; 52 | 53 | ViewHolder(View itemView) { 54 | super(itemView); 55 | ButterKnife.bind(this, itemView); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/blue_button.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/card_shape.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/indicator_shape.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/tag_shape.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_home.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 13 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_news.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_photo.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_photo_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 14 | 20 | 21 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/layout/include_line.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_base_content_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 15 | 16 | 20 | 21 | 26 | 27 | 28 | 34 | 35 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 57 | 58 | 63 | 64 | 65 | 66 | 71 | 72 | 77 | 78 | 86 | 87 | 93 | 94 | 102 | 103 | 104 | 110 | 111 | 115 | 116 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_content_single_image.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_hot_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 16 | 17 | 24 | 25 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 60 | 61 | 66 | 67 | 68 | 69 | 75 | 76 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_image.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_mult_img_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_music_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 13 | 14 | 18 | 19 | 24 | 25 | 26 | 27 | 28 | 34 | 35 | 41 | 42 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_recommend_card_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 17 | 18 | 23 | 24 | 34 | 35 | 36 | 44 | 45 | 51 | 52 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_recommend_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 20 | 21 | 26 | 27 | 28 | 29 | 38 | 39 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_video_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 11 | 12 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_weather_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 16 | 17 | 21 | 22 | 32 | 33 | 39 | 40 | 45 | 46 | 47 | 48 | 49 | 56 | 57 | 65 | 66 | 67 | 68 | 73 | 74 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcq123/MultiTypeImageLayout/f9610f51caaff8039b6346f936d02b4f08dbfd01/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcq123/MultiTypeImageLayout/f9610f51caaff8039b6346f936d02b4f08dbfd01/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcq123/MultiTypeImageLayout/f9610f51caaff8039b6346f936d02b4f08dbfd01/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcq123/MultiTypeImageLayout/f9610f51caaff8039b6346f936d02b4f08dbfd01/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcq123/MultiTypeImageLayout/f9610f51caaff8039b6346f936d02b4f08dbfd01/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcq123/MultiTypeImageLayout/f9610f51caaff8039b6346f936d02b4f08dbfd01/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/arow_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcq123/MultiTypeImageLayout/f9610f51caaff8039b6346f936d02b4f08dbfd01/app/src/main/res/mipmap-xxhdpi/arow_right.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/arrow_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcq123/MultiTypeImageLayout/f9610f51caaff8039b6346f936d02b4f08dbfd01/app/src/main/res/mipmap-xxhdpi/arrow_down.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcq123/MultiTypeImageLayout/f9610f51caaff8039b6346f936d02b4f08dbfd01/app/src/main/res/mipmap-xxhdpi/close.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcq123/MultiTypeImageLayout/f9610f51caaff8039b6346f936d02b4f08dbfd01/app/src/main/res/mipmap-xxhdpi/delete.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcq123/MultiTypeImageLayout/f9610f51caaff8039b6346f936d02b4f08dbfd01/app/src/main/res/mipmap-xxhdpi/heart.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/hot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcq123/MultiTypeImageLayout/f9610f51caaff8039b6346f936d02b4f08dbfd01/app/src/main/res/mipmap-xxhdpi/hot.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcq123/MultiTypeImageLayout/f9610f51caaff8039b6346f936d02b4f08dbfd01/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcq123/MultiTypeImageLayout/f9610f51caaff8039b6346f936d02b4f08dbfd01/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcq123/MultiTypeImageLayout/f9610f51caaff8039b6346f936d02b4f08dbfd01/app/src/main/res/mipmap-xxhdpi/link.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/local.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcq123/MultiTypeImageLayout/f9610f51caaff8039b6346f936d02b4f08dbfd01/app/src/main/res/mipmap-xxhdpi/local.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/message.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcq123/MultiTypeImageLayout/f9610f51caaff8039b6346f936d02b4f08dbfd01/app/src/main/res/mipmap-xxhdpi/message.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/music.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcq123/MultiTypeImageLayout/f9610f51caaff8039b6346f936d02b4f08dbfd01/app/src/main/res/mipmap-xxhdpi/music.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcq123/MultiTypeImageLayout/f9610f51caaff8039b6346f936d02b4f08dbfd01/app/src/main/res/mipmap-xxhdpi/play.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/play_gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcq123/MultiTypeImageLayout/f9610f51caaff8039b6346f936d02b4f08dbfd01/app/src/main/res/mipmap-xxhdpi/play_gray.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcq123/MultiTypeImageLayout/f9610f51caaff8039b6346f936d02b4f08dbfd01/app/src/main/res/mipmap-xxhdpi/plus.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/share.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcq123/MultiTypeImageLayout/f9610f51caaff8039b6346f936d02b4f08dbfd01/app/src/main/res/mipmap-xxhdpi/share.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/weather01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcq123/MultiTypeImageLayout/f9610f51caaff8039b6346f936d02b4f08dbfd01/app/src/main/res/mipmap-xxhdpi/weather01.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/weather02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcq123/MultiTypeImageLayout/f9610f51caaff8039b6346f936d02b4f08dbfd01/app/src/main/res/mipmap-xxhdpi/weather02.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/weather03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcq123/MultiTypeImageLayout/f9610f51caaff8039b6346f936d02b4f08dbfd01/app/src/main/res/mipmap-xxhdpi/weather03.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/weather04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcq123/MultiTypeImageLayout/f9610f51caaff8039b6346f936d02b4f08dbfd01/app/src/main/res/mipmap-xxhdpi/weather04.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/weather05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcq123/MultiTypeImageLayout/f9610f51caaff8039b6346f936d02b4f08dbfd01/app/src/main/res/mipmap-xxhdpi/weather05.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcq123/MultiTypeImageLayout/f9610f51caaff8039b6346f936d02b4f08dbfd01/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcq123/MultiTypeImageLayout/f9610f51caaff8039b6346f936d02b4f08dbfd01/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | #eee 8 | #ffffff 9 | 10 | #eff0f1 11 | #3b86af 12 | #929292 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12dp 5 | 25dp 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 多Item列表布局 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.3.0' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | maven { url 'https://jitpack.io' } 19 | } 20 | } 21 | 22 | task clean(type: Delete) { 23 | delete rootProject.buildDir 24 | } 25 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dcq123/MultiTypeImageLayout/f9610f51caaff8039b6346f936d02b4f08dbfd01/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Apr 07 10:50:21 CST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------