master
ZhangMengyao 3 years ago
parent 0f4d6cb26f
commit 3d84080de4

@ -0,0 +1,55 @@
# Built application files
*.apk
*.ap_
# Files for the ART/Dalvik VM
*.dex
# Java class files
*.class
# Generated files
bin/
gen/
out/
# Gradle files
.gradle/
build/
# Local configuration file (sdk path, etc)
local.properties
# Proguard folder generated by Eclipse
proguard/
# Log Files
*.log
# Android Studio Navigation editor temp files
.navigation/
# Android Studio captures folder
captures/
# Intellij
*.iml
.idea/workspace.xml
.idea/tasks.xml
.idea/gradle.xml
.idea/dictionaries
.idea/libraries
# Keystore files
*.jks
# External native build folder generated in Android Studio 2.2 and later
.externalNativeBuild
# Google Services (e.g. APIs or Firebase)
google-services.json
# Freeline
freeline.py
freeline/
freeline_project_description.json

@ -0,0 +1,9 @@
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
.externalNativeBuild

@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="1.8" />
</component>
</project>

@ -0,0 +1,3 @@
<component name="ProjectDictionaryState">
<dictionary name="moos" />
</component>

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="BintrayJCenter" />
<option name="name" value="BintrayJCenter" />
<option name="url" value="https://jcenter.bintray.com/" />
</remote-repository>
<remote-repository>
<option name="id" value="Google" />
<option name="name" value="Google" />
<option name="url" value="https://dl.google.com/dl/android/maven2/" />
</remote-repository>
</component>
</project>

@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="NullableNotNullManager">
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
<option name="myNullables">
<value>
<list size="4">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
</list>
</value>
</option>
<option name="myNotNulls">
<value>
<list size="4">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
</list>
</value>
</option>
</component>
<component name="ProjectInspectionProfilesVisibleTreeState">
<entry key="Project Default">
<profile-state>
<expanded-state>
<State>
<id />
</State>
<State>
<id>Android</id>
</State>
<State>
<id>CorrectnessLintAndroid</id>
</State>
<State>
<id>Java</id>
</State>
<State>
<id>LintAndroid</id>
</State>
<State>
<id>Probable bugsJava</id>
</State>
<State>
<id>RELAX NG</id>
</State>
</expanded-state>
<selected-state>
<State>
<id>Android</id>
</State>
</selected-state>
</profile-state>
</entry>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
<component name="masterDetails">
<states>
<state key="Copyright.UI">
<settings>
<splitter-proportions>
<option name="proportions">
<list>
<option value="0.2" />
</list>
</option>
</splitter-proportions>
</settings>
</state>
<state key="ScopeChooserConfigurable.UI">
<settings>
<splitter-proportions>
<option name="proportions">
<list>
<option value="0.2" />
</list>
</option>
</splitter-proportions>
</settings>
</state>
</states>
</component>
</project>

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/modules/CommentWithReplyList.iml" filepath="$PROJECT_DIR$/.idea/modules/CommentWithReplyList.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/app/CommentWithReplyList.app.iml" filepath="$PROJECT_DIR$/.idea/modules/app/CommentWithReplyList.app.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/app/CommentWithReplyList.app.androidTest.iml" filepath="$PROJECT_DIR$/.idea/modules/app/CommentWithReplyList.app.androidTest.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/app/CommentWithReplyList.app.main.iml" filepath="$PROJECT_DIR$/.idea/modules/app/CommentWithReplyList.app.main.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/app/CommentWithReplyList.app.unitTest.iml" filepath="$PROJECT_DIR$/.idea/modules/app/CommentWithReplyList.app.unitTest.iml" />
</modules>
</component>
</project>

@ -0,0 +1,32 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.moos.example"
minSdkVersion 21
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:2.0.4'
testImplementation 'junit:junit:4.12'
implementation 'com.android.support:design:28.0.0'
implementation 'de.hdodenhof:circleimageview:2.1.0'
implementation 'com.github.bumptech.glide:glide:3.7.0'
implementation 'com.google.code.gson:gson:2.7'
}

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

@ -0,0 +1,26 @@
package com.moos.example;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() throws Exception {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("com.moos.example", appContext.getPackageName());
}
}

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.moos.example">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

@ -0,0 +1,304 @@
package com.moos.example;
import android.graphics.Color;
import android.support.design.widget.BottomSheetBehavior;
import android.support.design.widget.BottomSheetDialog;
import android.support.design.widget.CollapsingToolbarLayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ExpandableListView;
import android.widget.TextView;
import android.widget.Toast;
import com.google.gson.Gson;
import com.moos.example.adapter.CommentExpandAdapter;
import com.moos.example.bean.CommentBean;
import com.moos.example.bean.CommentDetailBean;
import com.moos.example.bean.ReplyDetailBean;
import com.moos.example.view.CommentExpandableListView;
import java.util.List;
/**
* by moos on 2018/04/20
*/
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = "MainActivity";
private android.support.v7.widget.Toolbar toolbar;
private TextView bt_comment;
private CommentExpandableListView expandableListView;
private CommentExpandAdapter adapter;
private CommentBean commentBean;
private List<CommentDetailBean> commentsList;
private BottomSheetDialog dialog;
private String testJson = "{\n" +
"\t\"code\": 1000,\n" +
"\t\"message\": \"查看评论成功\",\n" +
"\t\"data\": {\n" +
"\t\t\"total\": 3,\n" +
"\t\t\"list\": [{\n" +
"\t\t\t\t\"id\": 42,\n" +
"\t\t\t\t\"nickName\": \"程序猿\",\n" +
"\t\t\t\t\"userLogo\": \"http://ucardstorevideo.b0.upaiyun.com/userLogo/9fa13ec6-dddd-46cb-9df0-4bbb32d83fc1.png\",\n" +
"\t\t\t\t\"content\": \"时间是一切财富中最宝贵的财富。\",\n" +
"\t\t\t\t\"imgId\": \"xcclsscrt0tev11ok364\",\n" +
"\t\t\t\t\"replyTotal\": 1,\n" +
"\t\t\t\t\"createDate\": \"三分钟前\",\n" +
"\t\t\t\t\"replyList\": [{\n" +
"\t\t\t\t\t\"nickName\": \"沐風\",\n" +
"\t\t\t\t\t\"userLogo\": \"http://ucardstorevideo.b0.upaiyun.com/userLogo/9fa13ec6-dddd-46cb-9df0-4bbb32d83fc1.png\",\n" +
"\t\t\t\t\t\"id\": 40,\n" +
"\t\t\t\t\t\"commentId\": \"42\",\n" +
"\t\t\t\t\t\"content\": \"时间总是在不经意中擦肩而过,不留一点痕迹.\",\n" +
"\t\t\t\t\t\"status\": \"01\",\n" +
"\t\t\t\t\t\"createDate\": \"一个小时前\"\n" +
"\t\t\t\t}]\n" +
"\t\t\t},\n" +
"\t\t\t{\n" +
"\t\t\t\t\"id\": 41,\n" +
"\t\t\t\t\"nickName\": \"设计狗\",\n" +
"\t\t\t\t\"userLogo\": \"http://ucardstorevideo.b0.upaiyun.com/userLogo/9fa13ec6-dddd-46cb-9df0-4bbb32d83fc1.png\",\n" +
"\t\t\t\t\"content\": \"这世界要是没有爱情,它在我们心中还会有什么意义!这就如一盏没有亮光的走马灯。\",\n" +
"\t\t\t\t\"imgId\": \"xcclsscrt0tev11ok364\",\n" +
"\t\t\t\t\"replyTotal\": 1,\n" +
"\t\t\t\t\"createDate\": \"一天前\",\n" +
"\t\t\t\t\"replyList\": [{\n" +
"\t\t\t\t\t\"nickName\": \"沐風\",\n" +
"\t\t\t\t\t\"userLogo\": \"http://ucardstorevideo.b0.upaiyun.com/userLogo/9fa13ec6-dddd-46cb-9df0-4bbb32d83fc1.png\",\n" +
"\t\t\t\t\t\"commentId\": \"41\",\n" +
"\t\t\t\t\t\"content\": \"时间总是在不经意中擦肩而过,不留一点痕迹.\",\n" +
"\t\t\t\t\t\"status\": \"01\",\n" +
"\t\t\t\t\t\"createDate\": \"三小时前\"\n" +
"\t\t\t\t}]\n" +
"\t\t\t},\n" +
"\t\t\t{\n" +
"\t\t\t\t\"id\": 40,\n" +
"\t\t\t\t\"nickName\": \"产品喵\",\n" +
"\t\t\t\t\"userLogo\": \"http://ucardstorevideo.b0.upaiyun.com/userLogo/9fa13ec6-dddd-46cb-9df0-4bbb32d83fc1.png\",\n" +
"\t\t\t\t\"content\": \"笨蛋自以为聪明,聪明人才知道自己是笨蛋。\",\n" +
"\t\t\t\t\"imgId\": \"xcclsscrt0tev11ok364\",\n" +
"\t\t\t\t\"replyTotal\": 0,\n" +
"\t\t\t\t\"createDate\": \"三天前\",\n" +
"\t\t\t\t\"replyList\": []\n" +
"\t\t\t}\n" +
"\t\t]\n" +
"\t}\n" +
"}";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
toolbar = (Toolbar) findViewById(R.id.toolbar);
expandableListView = (CommentExpandableListView) findViewById(R.id.detail_page_lv_comment);
bt_comment = (TextView) findViewById(R.id.detail_page_do_comment);
bt_comment.setOnClickListener(this);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
CollapsingToolbarLayout collapsingToolbar =
(CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
collapsingToolbar.setTitle("详情");
commentsList = generateTestData();
initExpandableListView(commentsList);
}
/**
*
*/
private void initExpandableListView(final List<CommentDetailBean> commentList){
expandableListView.setGroupIndicator(null);
//默认展开所有回复
adapter = new CommentExpandAdapter(this, commentList);
expandableListView.setAdapter(adapter);
for(int i = 0; i<commentList.size(); i++){
expandableListView.expandGroup(i);
}
expandableListView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
@Override
public boolean onGroupClick(ExpandableListView expandableListView, View view, int groupPosition, long l) {
boolean isExpanded = expandableListView.isGroupExpanded(groupPosition);
Log.e(TAG, "onGroupClick: 当前的评论id>>>"+commentList.get(groupPosition).getId());
// if(isExpanded){
// expandableListView.collapseGroup(groupPosition);
// }else {
// expandableListView.expandGroup(groupPosition, true);
// }
showReplyDialog(groupPosition);
return true;
}
});
expandableListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView expandableListView, View view, int groupPosition, int childPosition, long l) {
Toast.makeText(MainActivity.this,"点击了回复",Toast.LENGTH_SHORT).show();
return false;
}
});
expandableListView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
@Override
public void onGroupExpand(int groupPosition) {
//toast("展开第"+groupPosition+"个分组");
}
});
}
/**
* by moos on 2018/04/20
* func:
* @return
*/
private List<CommentDetailBean> generateTestData(){
Gson gson = new Gson();
commentBean = gson.fromJson(testJson, CommentBean.class);
List<CommentDetailBean> commentList = commentBean.getData().getList();
return commentList;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if(item.getItemId() == android.R.id.home){
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onClick(View view) {
if(view.getId() == R.id.detail_page_do_comment){
showCommentDialog();
}
}
/**
* by moos on 2018/04/20
* func:
*/
private void showCommentDialog(){
dialog = new BottomSheetDialog(this);
View commentView = LayoutInflater.from(this).inflate(R.layout.comment_dialog_layout,null);
final EditText commentText = (EditText) commentView.findViewById(R.id.dialog_comment_et);
final Button bt_comment = (Button) commentView.findViewById(R.id.dialog_comment_bt);
dialog.setContentView(commentView);
/**
* bsd
*/
View parent = (View) commentView.getParent();
BottomSheetBehavior behavior = BottomSheetBehavior.from(parent);
commentView.measure(0,0);
behavior.setPeekHeight(commentView.getMeasuredHeight());
bt_comment.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String commentContent = commentText.getText().toString().trim();
if(!TextUtils.isEmpty(commentContent)){
//commentOnWork(commentContent);
dialog.dismiss();
CommentDetailBean detailBean = new CommentDetailBean("小明", commentContent,"刚刚");
adapter.addTheCommentData(detailBean);
Toast.makeText(MainActivity.this,"评论成功",Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(MainActivity.this,"评论内容不能为空",Toast.LENGTH_SHORT).show();
}
}
});
commentText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if(!TextUtils.isEmpty(charSequence) && charSequence.length()>2){
bt_comment.setBackgroundColor(Color.parseColor("#FFB568"));
}else {
bt_comment.setBackgroundColor(Color.parseColor("#D8D8D8"));
}
}
@Override
public void afterTextChanged(Editable editable) {
}
});
dialog.show();
}
/**
* by moos on 2018/04/20
* func:
*/
private void showReplyDialog(final int position){
dialog = new BottomSheetDialog(this);
View commentView = LayoutInflater.from(this).inflate(R.layout.comment_dialog_layout,null);
final EditText commentText = (EditText) commentView.findViewById(R.id.dialog_comment_et);
final Button bt_comment = (Button) commentView.findViewById(R.id.dialog_comment_bt);
commentText.setHint("回复 " + commentsList.get(position).getNickName() + " 的评论:");
dialog.setContentView(commentView);
bt_comment.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String replyContent = commentText.getText().toString().trim();
if(!TextUtils.isEmpty(replyContent)){
dialog.dismiss();
ReplyDetailBean detailBean = new ReplyDetailBean("小红",replyContent);
adapter.addTheReplyData(detailBean, position);
expandableListView.expandGroup(position);
Toast.makeText(MainActivity.this,"回复成功",Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(MainActivity.this,"回复内容不能为空",Toast.LENGTH_SHORT).show();
}
}
});
commentText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if(!TextUtils.isEmpty(charSequence) && charSequence.length()>2){
bt_comment.setBackgroundColor(Color.parseColor("#FFB568"));
}else {
bt_comment.setBackgroundColor(Color.parseColor("#D8D8D8"));
}
}
@Override
public void afterTextChanged(Editable editable) {
}
});
dialog.show();
}
}

@ -0,0 +1,233 @@
package com.moos.example.adapter;
import android.content.Context;
import android.graphics.Color;
import android.support.design.widget.BottomSheetDialog;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.moos.example.R;
import com.moos.example.bean.CommentDetailBean;
import com.moos.example.bean.ReplyDetailBean;
import java.util.ArrayList;
import java.util.List;
import de.hdodenhof.circleimageview.CircleImageView;
/**
* Author: Moos
* E-mail: moosphon@gmail.com
* Date: 18/4/20.
* Desc:
*/
public class CommentExpandAdapter extends BaseExpandableListAdapter {
private static final String TAG = "CommentExpandAdapter";
private List<CommentDetailBean> commentBeanList;
private List<ReplyDetailBean> replyBeanList;
private Context context;
private int pageIndex = 1;
public CommentExpandAdapter(Context context, List<CommentDetailBean> commentBeanList) {
this.context = context;
this.commentBeanList = commentBeanList;
}
@Override
public int getGroupCount() {
return commentBeanList.size();
}
@Override
public int getChildrenCount(int i) {
if(commentBeanList.get(i).getReplyList() == null){
return 0;
}else {
return commentBeanList.get(i).getReplyList().size()>0 ? commentBeanList.get(i).getReplyList().size():0;
}
}
@Override
public Object getGroup(int i) {
return commentBeanList.get(i);
}
@Override
public Object getChild(int i, int i1) {
return commentBeanList.get(i).getReplyList().get(i1);
}
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return getCombinedChildId(groupPosition, childPosition);
}
@Override
public boolean hasStableIds() {
return true;
}
boolean isLike = false;
@Override
public View getGroupView(final int groupPosition, boolean isExpand, View convertView, ViewGroup viewGroup) {
final GroupHolder groupHolder;
if(convertView == null){
convertView = LayoutInflater.from(context).inflate(R.layout.comment_item_layout, viewGroup, false);
groupHolder = new GroupHolder(convertView);
convertView.setTag(groupHolder);
}else {
groupHolder = (GroupHolder) convertView.getTag();
}
Glide.with(context).load(R.drawable.user_other)
.diskCacheStrategy(DiskCacheStrategy.RESULT)
.error(R.mipmap.ic_launcher)
.centerCrop()
.into(groupHolder.logo);
groupHolder.tv_name.setText(commentBeanList.get(groupPosition).getNickName());
groupHolder.tv_time.setText(commentBeanList.get(groupPosition).getCreateDate());
groupHolder.tv_content.setText(commentBeanList.get(groupPosition).getContent());
groupHolder.iv_like.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(isLike){
isLike = false;
groupHolder.iv_like.setColorFilter(Color.parseColor("#aaaaaa"));
}else {
isLike = true;
groupHolder.iv_like.setColorFilter(Color.parseColor("#FF5C5C"));
}
}
});
return convertView;
}
@Override
public View getChildView(final int groupPosition, int childPosition, boolean b, View convertView, ViewGroup viewGroup) {
final ChildHolder childHolder;
if(convertView == null){
convertView = LayoutInflater.from(context).inflate(R.layout.comment_reply_item_layout,viewGroup, false);
childHolder = new ChildHolder(convertView);
convertView.setTag(childHolder);
}
else {
childHolder = (ChildHolder) convertView.getTag();
}
String replyUser = commentBeanList.get(groupPosition).getReplyList().get(childPosition).getNickName();
if(!TextUtils.isEmpty(replyUser)){
childHolder.tv_name.setText(replyUser + ":");
}else {
childHolder.tv_name.setText("无名"+":");
}
childHolder.tv_content.setText(commentBeanList.get(groupPosition).getReplyList().get(childPosition).getContent());
return convertView;
}
@Override
public boolean isChildSelectable(int i, int i1) {
return true;
}
private class GroupHolder{
private CircleImageView logo;
private TextView tv_name, tv_content, tv_time;
private ImageView iv_like;
public GroupHolder(View view) {
logo = (CircleImageView) view.findViewById(R.id.comment_item_logo);
tv_content = (TextView) view.findViewById(R.id.comment_item_content);
tv_name = (TextView) view.findViewById(R.id.comment_item_userName);
tv_time = (TextView) view.findViewById(R.id.comment_item_time);
iv_like = (ImageView) view.findViewById(R.id.comment_item_like);
}
}
private class ChildHolder{
private TextView tv_name, tv_content;
public ChildHolder(View view) {
tv_name = (TextView) view.findViewById(R.id.reply_item_user);
tv_content = (TextView) view.findViewById(R.id.reply_item_content);
}
}
/**
* by moos on 2018/04/20
* func:
* @param commentDetailBean
*/
public void addTheCommentData(CommentDetailBean commentDetailBean){
if(commentDetailBean!=null){
commentBeanList.add(commentDetailBean);
notifyDataSetChanged();
}else {
throw new IllegalArgumentException("评论数据为空!");
}
}
/**
* by moos on 2018/04/20
* func:
* @param replyDetailBean
*/
public void addTheReplyData(ReplyDetailBean replyDetailBean, int groupPosition){
if(replyDetailBean!=null){
Log.e(TAG, "addTheReplyData: >>>>该刷新回复列表了:"+replyDetailBean.toString() );
if(commentBeanList.get(groupPosition).getReplyList() != null ){
commentBeanList.get(groupPosition).getReplyList().add(replyDetailBean);
}else {
List<ReplyDetailBean> replyList = new ArrayList<>();
replyList.add(replyDetailBean);
commentBeanList.get(groupPosition).setReplyList(replyList);
}
notifyDataSetChanged();
}else {
throw new IllegalArgumentException("回复数据为空!");
}
}
/**
* by moos on 2018/04/20
* func:
* @param replyBeanList
* @param groupPosition
*/
private void addReplyList(List<ReplyDetailBean> replyBeanList, int groupPosition){
if(commentBeanList.get(groupPosition).getReplyList() != null ){
commentBeanList.get(groupPosition).getReplyList().clear();
commentBeanList.get(groupPosition).getReplyList().addAll(replyBeanList);
}else {
commentBeanList.get(groupPosition).setReplyList(replyBeanList);
}
notifyDataSetChanged();
}
}

@ -0,0 +1,54 @@
package com.moos.example.bean;
import java.util.List;
/**
* Created by moos on 2018/4/20.
*/
public class CommentBean {
private int code;
private String message;
private Data data;
public void setCode(int code) {
this.code = code;
}
public int getCode() {
return code;
}
public void setMessage(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
public void setData(Data data) {
this.data = data;
}
public Data getData() {
return data;
}
public class Data {
private int total;
private List<CommentDetailBean> list;
public void setTotal(int total) {
this.total = total;
}
public int getTotal() {
return total;
}
public void setList(List<CommentDetailBean> list) {
this.list = list;
}
public List<CommentDetailBean> getList() {
return list;
}
}
}

@ -0,0 +1,80 @@
package com.moos.example.bean;
import java.util.List;
/**
* Created by moos on 2018/4/20.
*/
public class CommentDetailBean {
private int id;
private String nickName;
private String userLogo;
private String content;
private String imgId;
private int replyTotal;
private String createDate;
private List<ReplyDetailBean> replyList;
public CommentDetailBean(String nickName, String content, String createDate) {
this.nickName = nickName;
this.content = content;
this.createDate = createDate;
}
public void setId(int id) {
this.id = id;
}
public int getId() {
return id;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public String getNickName() {
return nickName;
}
public void setUserLogo(String userLogo) {
this.userLogo = userLogo;
}
public String getUserLogo() {
return userLogo;
}
public void setContent(String content) {
this.content = content;
}
public String getContent() {
return content;
}
public void setImgId(String imgId) {
this.imgId = imgId;
}
public String getImgId() {
return imgId;
}
public void setReplyTotal(int replyTotal) {
this.replyTotal = replyTotal;
}
public int getReplyTotal() {
return replyTotal;
}
public void setCreateDate(String createDate) {
this.createDate = createDate;
}
public String getCreateDate() {
return createDate;
}
public void setReplyList(List<ReplyDetailBean> replyList) {
this.replyList = replyList;
}
public List<ReplyDetailBean> getReplyList() {
return replyList;
}
}

@ -0,0 +1,70 @@
package com.moos.example.bean;
/**
* Created by moos on 2018/4/20.
*/
public class ReplyDetailBean {
private String nickName;
private String userLogo;
private int id;
private String commentId;
private String content;
private String status;
private String createDate;
public ReplyDetailBean(String nickName, String content) {
this.nickName = nickName;
this.content = content;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public String getNickName() {
return nickName;
}
public void setUserLogo(String userLogo) {
this.userLogo = userLogo;
}
public String getUserLogo() {
return userLogo;
}
public void setId(int id) {
this.id = id;
}
public int getId() {
return id;
}
public void setCommentId(String commentId) {
this.commentId = commentId;
}
public String getCommentId() {
return commentId;
}
public void setContent(String content) {
this.content = content;
}
public String getContent() {
return content;
}
public void setStatus(String status) {
this.status = status;
}
public String getStatus() {
return status;
}
public void setCreateDate(String createDate) {
this.createDate = createDate;
}
public String getCreateDate() {
return createDate;
}
}

@ -0,0 +1,83 @@
package com.moos.example.view;
import android.content.Context;
import android.os.Build;
import android.support.v4.view.NestedScrollingChild;
import android.support.v4.view.NestedScrollingChildHelper;
import android.util.AttributeSet;
import android.widget.ExpandableListView;
/**
* Author: Moos
* E-mail: moosphon@gmail.com
* Date: 18/4/20.
* Desc: ExpandableListView,CoordinatorLayout
*/
public class CommentExpandableListView extends ExpandableListView implements NestedScrollingChild{
private NestedScrollingChildHelper mScrollingChildHelper;
public CommentExpandableListView(Context context, AttributeSet attrs) {
super(context, attrs);
mScrollingChildHelper = new NestedScrollingChildHelper(this);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
setNestedScrollingEnabled(true);
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
@Override
public void setNestedScrollingEnabled(boolean enabled) {
mScrollingChildHelper.setNestedScrollingEnabled(enabled);
}
@Override
public boolean isNestedScrollingEnabled() {
return mScrollingChildHelper.isNestedScrollingEnabled();
}
@Override
public boolean startNestedScroll(int axes) {
return mScrollingChildHelper.startNestedScroll(axes);
}
@Override
public void stopNestedScroll() {
mScrollingChildHelper.stopNestedScroll();
}
@Override
public boolean hasNestedScrollingParent() {
return mScrollingChildHelper.hasNestedScrollingParent();
}
@Override
public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed,
int dyUnconsumed, int[] offsetInWindow) {
return mScrollingChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed,
dxUnconsumed, dyUnconsumed, offsetInWindow);
}
@Override
public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
return mScrollingChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
}
@Override
public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
return mScrollingChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
}
@Override
public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
return mScrollingChildHelper.dispatchNestedPreFling(velocityX, velocityY);
}
}

@ -0,0 +1,34 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillType="evenOdd"
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
android:strokeColor="#00000000"
android:strokeWidth="1">
<aapt:attr name="android:fillColor">
<gradient
android:endX="78.5885"
android:endY="90.9159"
android:startX="48.7653"
android:startY="61.0927"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
android:strokeColor="#00000000"
android:strokeWidth="1" />
</vector>

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#f3f3f3" />
<corners android:radius="16dp"/>
</shape>
</item>
<item android:state_pressed="false">
<shape>
<solid android:color="#eeeeee" />
<corners android:radius="16dp"/>
</shape>
</item>
</selector>

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_window_focused="false">
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#ffffff" />
<corners android:radius="3dp"/>
</shape>
</item>
<item android:state_window_focused="true">
<shape>
<solid android:color="#F8F8F8" />
<corners android:radius="3dp"/>
</shape>
</item>
</selector>

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillColor="#26A69A"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
</vector>

@ -0,0 +1,212 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:fitsSystemWindows="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.moos.example.MainActivity">
<android.support.design.widget.CoordinatorLayout
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="248dp"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
android:fitsSystemWindows="true">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
android:fitsSystemWindows="true"
app:contentScrim="#212121"
app:expandedTitleMarginStart="48dp"
app:expandedTitleMarginEnd="64dp">
<ImageView
android:id="@+id/detail_page_image"
android:layout_width="match_parent"
android:layout_height="248dp"
android:scaleType="centerCrop"
android:src="@drawable/teaser"
android:fitsSystemWindows="true"
app:layout_collapseMode="parallax" />
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:layout_collapseMode="pin" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/detail_page_above_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="12dp"
android:layout_marginBottom="10dp"
android:gravity="center_vertical">
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/detail_page_userLogo"
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/user_logo"
android:layout_marginLeft="16dp"
app:civ_border_width="1dp"
app:civ_border_color="@android:color/white"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginLeft="6dp"
android:orientation="vertical">
<TextView
android:id="@+id/detail_page_userName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#5B595A"
android:textSize="14sp"
android:text="沐风" />
<TextView
android:id="@+id/detail_page_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1小时前"
android:textSize="12sp"
android:layout_marginTop="3dp"
android:textColor="#989898"/>
</LinearLayout>
<ImageView
android:id="@+id/detail_page_focus"
android:layout_width="30dp"
android:layout_height="30dp"
android:src="@drawable/icon_focus"
android:layout_margin="12dp"
android:padding="6dp"/>
</LinearLayout>
<TextView
android:id="@+id/detail_page_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="诗和远方"
android:layout_marginLeft="18dp"
android:layout_marginTop="12dp"
android:layout_marginBottom="6dp"
android:textSize="18sp"
android:textColor="#363636"/>
<TextView
android:id="@+id/detail_page_story"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="18dp"
android:text="水光潋滟晴方好,山色空蒙雨亦奇。\n欲把西湖比西子淡抹浓妆总相宜。"
android:maxLines="10"
android:ellipsize="end"
android:layout_marginRight="10dp"
android:textSize="14sp"
android:textColor="#6e6e6e"/>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_marginTop="20dp"
android:layout_marginRight="16dp"
android:layout_marginLeft="16dp"
android:background="#e6e6e6"/>
</LinearLayout>
<LinearLayout
android:id="@+id/detail_page_comment_container"
android:layout_below="@+id/detail_page_above_container"
android:layout_marginTop="20dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.moos.example.view.CommentExpandableListView
android:id="@+id/detail_page_lv_comment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@null"
android:layout_marginBottom="64dp"
android:listSelector="@android:color/transparent"
android:scrollbars="none"/>
</LinearLayout>
</RelativeLayout>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="58dp"
android:layout_alignParentBottom="true"
android:background="@android:color/white"
android:elevation="2dp"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:id="@+id/detail_page_do_comment"
android:layout_width="0dp"
android:layout_height="34dp"
android:layout_weight="1"
android:textColor="#B6B6B6"
android:textSize="12sp"
android:text="说点什么吧..."
android:background="@drawable/comment_bt_selector"
android:layout_marginLeft="12dp"
android:layout_marginRight="22dp"
android:gravity="center_vertical"
android:paddingLeft="18dp"/>
<ImageView
android:layout_width="22dp"
android:layout_height="22dp"
android:src="@drawable/icon_collect"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#9A9A9A"
android:textSize="14sp"
android:layout_marginLeft="10dp"
android:text="32"/>
<ImageView
android:layout_width="22dp"
android:layout_height="22dp"
android:src="@drawable/icon_work_like"
android:layout_marginLeft="20dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#9A9A9A"
android:textSize="14sp"
android:layout_marginLeft="10dp"
android:layout_marginRight="14dp"
android:text="66"/>
</LinearLayout>
</RelativeLayout>

@ -0,0 +1,35 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="@+id/dialog_comment_et"
android:layout_width="match_parent"
android:layout_height="105dp"
android:background="@drawable/comment_dialog_et_selector"
android:layout_margin="12dp"
android:hint="请输入评论内容..."
android:textSize="14sp"
android:gravity="left|top"
android:paddingLeft="15dp"
android:paddingTop="12dp"
android:textColorHint="#929292"
android:textColor="#808080"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/dialog_comment_bt"
android:layout_width="72dp"
android:layout_height="32dp"
android:background="#D8D8D8"
android:layout_marginBottom="14dp"
android:textColor="@android:color/white"
android:textSize="14sp"
android:layout_marginTop="6dp"
android:layout_alignParentRight="true"
android:layout_marginRight="12dp"
android:text="发布"/>
</RelativeLayout>
</LinearLayout>

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginTop="12dp"
android:orientation="horizontal"
android:gravity="center_vertical">
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/comment_item_logo"
android:layout_width="28dp"
android:layout_height="28dp"
android:src="@drawable/user_logo"
android:layout_marginLeft="14dp"
android:layout_marginRight="6dp"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginLeft="6dp"
android:orientation="vertical">
<TextView
android:id="@+id/comment_item_userName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#5B595A"
android:textSize="14sp"
android:text="沐风" />
<TextView
android:id="@+id/comment_item_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1小时前"
android:textSize="12sp"
android:layout_marginTop="3dp"
android:textColor="#989898"/>
</LinearLayout>
<ImageView
android:id="@+id/comment_item_like"
android:layout_width="34dp"
android:layout_height="34dp"
android:theme="?android:selectableItemBackgroundBorderless"
android:src="@drawable/icon_comment_like"
android:layout_margin="10dp"
android:padding="8dp"/>
</LinearLayout>
<TextView
android:id="@+id/comment_item_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginTop="6dp"
android:textColor="#484848"
android:textSize="14sp"
android:layout_marginLeft="52dp"
android:layout_marginRight="24dp"
android:text="从前有座山,山里有座庙,庙里有个老和尚"/>
</LinearLayout>

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<View
android:layout_width="match_parent"
android:layout_height="10dp"
android:layout_marginLeft="48dp"
android:layout_marginRight="32dp"
android:background="#F6F6F6"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:layout_marginLeft="48dp"
android:layout_marginRight="32dp"
android:orientation="horizontal"
android:background="#F6F6F6">
<TextView
android:id="@+id/reply_item_user"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="沐风:"
android:textSize="14sp"
android:textColor="#626262"/>
<TextView
android:id="@+id/reply_item_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="4dp"
android:paddingRight="8dp"
android:maxLines="10"
android:ellipsize="end"
android:textColor="#949494"
android:textSize="14sp"
android:text="世上本没有路,走的人多了,也就成了路"/>
</LinearLayout>
</LinearLayout>

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
</resources>

@ -0,0 +1,3 @@
<resources>
<string name="app_name">CommentWithReplyList</string>
</resources>

@ -0,0 +1,11 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@android:color/black</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>

@ -0,0 +1,17 @@
package com.moos.example;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

@ -0,0 +1,27 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.2.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}

@ -0,0 +1,17 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
android.overridePathCheck=true
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true

@ -0,0 +1,6 @@
#Thu Nov 24 20:23:05 CST 2022
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME

@ -0,0 +1,160 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

@ -0,0 +1,90 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Moos
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -0,0 +1,10 @@
# CommentWithReplyView-master
基于ExpandableListView实现评论和回复的功能。
>![效果图](https://github.com/Moosphan/CommentWithReplyView-master/blob/d8abe02ccb0ca42d40f330ab3f3c68cbad4af029/CommentWithReplyList/art/comment_sample.gif)
## 说明
- 提供了模拟数据,实现评论和回复的插入数据
- 对评论和回复数据进行了异常处理
- material design风格的详情页
- 处理了NestedScrollView、ExpandableListView和CoordinatorLayout的嵌套问题
- 点击某条评论,即可@ta进行回复
Loading…
Cancel
Save