Commit e964d03e0d170da48d804423605ba422cba8c47c
no message
... | ... | @@ -10,6 +10,7 @@ |
10 | 10 | <option value="$PROJECT_DIR$" /> |
11 | 11 | <option value="$PROJECT_DIR$/app" /> |
12 | 12 | <option value="$PROJECT_DIR$/mvpsdk" /> |
13 | + <option value="$PROJECT_DIR$/mychartlibrary" /> | |
13 | 14 | <option value="$PROJECT_DIR$/processor" /> |
14 | 15 | <option value="$PROJECT_DIR$/roundedimageview-2.2.1" /> |
15 | 16 | </set> | ... | ... |
... | ... | @@ -4,6 +4,7 @@ |
4 | 4 | <modules> |
5 | 5 | <module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" /> |
6 | 6 | <module fileurl="file://$PROJECT_DIR$/mvpsdk/mvpsdk.iml" filepath="$PROJECT_DIR$/mvpsdk/mvpsdk.iml" /> |
7 | + <module fileurl="file://$PROJECT_DIR$/mychartlibrary/mychartlibrary.iml" filepath="$PROJECT_DIR$/mychartlibrary/mychartlibrary.iml" /> | |
7 | 8 | <module fileurl="file://$PROJECT_DIR$/parentwork.iml" filepath="$PROJECT_DIR$/parentwork.iml" /> |
8 | 9 | <module fileurl="file://$PROJECT_DIR$/processor/processor.iml" filepath="$PROJECT_DIR$/processor/processor.iml" /> |
9 | 10 | <module fileurl="file://$PROJECT_DIR$/roundedimageview-2.2.1/roundedimageview-2.2.1.iml" filepath="$PROJECT_DIR$/roundedimageview-2.2.1/roundedimageview-2.2.1.iml" /> | ... | ... |
... | ... | @@ -81,11 +81,8 @@ greendao { |
81 | 81 | schemaVersion 1//数据库版本升级 |
82 | 82 | } |
83 | 83 | dependencies { |
84 | - | |
85 | 84 | implementation fileTree(include: ['*.jar'], dir: 'libs') |
86 | - implementation 'com.android.support:appcompat-v7:26.1.0' | |
87 | 85 | implementation 'com.android.support.constraint:constraint-layout:1.0.2' |
88 | - implementation 'com.android.support:support-v4:26.1.0' | |
89 | 86 | testImplementation 'junit:junit:4.12' |
90 | 87 | androidTestImplementation 'com.android.support.test:runner:1.0.1' |
91 | 88 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' |
... | ... | @@ -97,6 +94,19 @@ dependencies { |
97 | 94 | compile 'me.leolin:ShortcutBadger:1.1.19@aar' |
98 | 95 | annotationProcessor 'com.google.dagger:dagger-compiler:2.12' |
99 | 96 | compile files('libs/processor.jar') |
100 | - | |
101 | 97 | compile 'com.contrarywind:Android-PickerView:4.1.3' |
102 | -} | |
103 | 98 | \ No newline at end of file |
99 | + implementation files('libs/gesture-imageview.jar') | |
100 | + implementation 'com.android.support:support-v4:27.1.0' | |
101 | + implementation project(':mychartlibrary') | |
102 | +} | |
103 | + | |
104 | +configurations.all { | |
105 | + resolutionStrategy.eachDependency { DependencyResolveDetails details -> | |
106 | + def requested = details.requested | |
107 | + if (requested.group == 'com.android.support') { | |
108 | + if (!requested.name.startsWith("multidex")) { | |
109 | + details.useVersion '26.1.0' | |
110 | + } | |
111 | + } | |
112 | + } | |
113 | +} | ... | ... |
... | ... | @@ -48,6 +48,7 @@ |
48 | 48 | <!-- 接收 SDK 消息广播权限, 第三方 APP 接入时,请将 com.netease.nim.demo 替换为自己的包名 --> |
49 | 49 | <uses-permission android:name="com.shunzhi.parent.permission.RECEIVE_MSG" /> |
50 | 50 | <uses-permission android:name="android.permission.CALL_PHONE" /> |
51 | + <uses-permission android:name="android.permission.RECORD_AUDIO" /> | |
51 | 52 | |
52 | 53 | <application |
53 | 54 | android:name=".AppContext" |
... | ... | @@ -117,7 +118,6 @@ |
117 | 118 | android:name="com.amap.api.v2.apikey" |
118 | 119 | android:value="1d130afb822d8a1019e6592cbaf10bcc" /> |
119 | 120 | |
120 | - | |
121 | 121 | <provider |
122 | 122 | android:name="android.support.v4.content.FileProvider" |
123 | 123 | android:authorities="com.shunzhi.parent.fileprovider" |
... | ... | @@ -147,6 +147,12 @@ |
147 | 147 | <!-- android:screenOrientation="portrait" --> |
148 | 148 | <!-- android:windowSoftInputMode="adjustPan|stateAlwaysHidden" /> --> |
149 | 149 | <activity |
150 | + android:name=".ui.activity.chartroom.RecyclerViewChatActivity" | |
151 | + android:theme="@style/AppBarTheme" | |
152 | + android:windowSoftInputMode="adjustResize|stateHidden" | |
153 | + android:screenOrientation="portrait" | |
154 | + /> | |
155 | + <activity | |
150 | 156 | android:name=".ui.activity.MyChildActivity" |
151 | 157 | android:screenOrientation="portrait" /> |
152 | 158 | <activity |
... | ... | @@ -178,6 +184,11 @@ |
178 | 184 | android:launchMode="singleInstance" |
179 | 185 | android:screenOrientation="portrait" |
180 | 186 | android:windowSoftInputMode="adjustPan|stateHidden" /> |
187 | + | |
188 | + <activity android:name=".ui.activity.chartroom.ImageViewActivity" | |
189 | + android:launchMode="singleInstance" | |
190 | + android:screenOrientation="portrait" | |
191 | + android:windowSoftInputMode="adjustPan|stateHidden"/> | |
181 | 192 | <activity |
182 | 193 | android:name=".ui.activity.binding.CheckInfoActivity" |
183 | 194 | android:launchMode="singleInstance" |
... | ... | @@ -212,21 +223,20 @@ |
212 | 223 | android:name=".ui.activity.BankActivity" |
213 | 224 | android:launchMode="singleInstance" |
214 | 225 | android:windowSoftInputMode="adjustPan|stateAlwaysHidden" /> |
215 | - | |
216 | 226 | <activity |
217 | 227 | android:name=".ui.activity.apply.ApplyReplaceCardActivity" |
218 | 228 | android:launchMode="singleInstance" |
219 | 229 | android:windowSoftInputMode="adjustPan|stateAlwaysHidden" /> |
220 | - | |
221 | 230 | <activity |
222 | 231 | android:name=".ui.activity.apply.ApplySigninActivity" |
223 | 232 | android:launchMode="singleInstance" /> |
224 | 233 | |
225 | 234 | <service |
226 | 235 | android:name=".ui.service.BadgeIntentService" |
227 | - android:exported="false"></service> | |
236 | + android:exported="false" /> | |
228 | 237 | |
229 | - <activity android:name=".ui.activity.message.MesageActivity"></activity> | |
238 | + <activity android:name=".ui.activity.message.MesageActivity" /> | |
239 | + <activity android:name=".ui.activity.message.LeaverMessagesActivity"></activity> | |
230 | 240 | </application> |
231 | 241 | |
232 | 242 | </manifest> |
233 | 243 | \ No newline at end of file | ... | ... |
... | ... | @@ -5,7 +5,6 @@ import android.content.Context; |
5 | 5 | import android.content.Intent; |
6 | 6 | import android.content.SharedPreferences; |
7 | 7 | import android.text.TextUtils; |
8 | -import android.util.Log; | |
9 | 8 | |
10 | 9 | import com.amap.api.location.AMapLocation; |
11 | 10 | import com.amap.api.location.AMapLocationClient; |
... | ... | @@ -18,6 +17,7 @@ import com.netease.nimlib.sdk.StatusBarNotificationConfig; |
18 | 17 | import com.netease.nimlib.sdk.auth.LoginInfo; |
19 | 18 | import com.share.mvpsdk.global.GlobalApplication; |
20 | 19 | import com.share.mvpsdk.helper.RetrofitCreateHelper; |
20 | +import com.shunzhi.mychartlibrary.db.BaseManager; | |
21 | 21 | import com.shunzhi.parent.bean.message.DaoMaster; |
22 | 22 | import com.shunzhi.parent.bean.message.DaoSession; |
23 | 23 | import com.shunzhi.parent.dbhelper.GreenDaoDatabaseOpenHelper; |
... | ... | @@ -70,7 +70,7 @@ public class AppContext extends GlobalApplication { |
70 | 70 | NIMClient.init(this, loginInfo(), options()); |
71 | 71 | if (null==AppConfig.getAppConfig(getContext()).get(AppConfig.DISTRICT)) |
72 | 72 | AppConfig.getAppConfig(getContext()).set(AppConfig.DISTRICT,"越城区"); |
73 | - | |
73 | + BaseManager.initOpenHelper(this); | |
74 | 74 | if (inMainProcess(this)) { |
75 | 75 | //开启地图地位 |
76 | 76 | initMapLocal(); | ... | ... |
... | ... | @@ -0,0 +1,14 @@ |
1 | +package com.shunzhi.parent.api; | |
2 | + | |
3 | +import com.google.gson.JsonObject; | |
4 | + | |
5 | +import io.reactivex.Observable; | |
6 | +import retrofit2.http.GET; | |
7 | +import retrofit2.http.Query; | |
8 | + | |
9 | +public interface GetLeaveMessageListAPI { | |
10 | + | |
11 | + @GET("api/XAWebCommon/GetLeaveMessageList") | |
12 | + Observable<JsonObject> GetLeaveMessageList(@Query("puserid") String puserid,@Query("suserid")String suserid); | |
13 | + | |
14 | +} | ... | ... |
... | ... | @@ -0,0 +1,34 @@ |
1 | +package com.shunzhi.parent.contract.leavermessage; | |
2 | + | |
3 | +public class LeaverMessage { | |
4 | + | |
5 | + public String id; | |
6 | + | |
7 | + public String sendUserId; | |
8 | + | |
9 | + public String receiveUserId; | |
10 | + | |
11 | + public String content; | |
12 | + | |
13 | + public String isRead; | |
14 | + | |
15 | + public String isRecall; | |
16 | + | |
17 | + public String intime; | |
18 | + | |
19 | + public String type; | |
20 | + | |
21 | + @Override | |
22 | + public String toString() { | |
23 | + return "LeaverMessage{" + | |
24 | + "id='" + id + '\'' + | |
25 | + ", sendUserId='" + sendUserId + '\'' + | |
26 | + ", receiveUserId='" + receiveUserId + '\'' + | |
27 | + ", content='" + content + '\'' + | |
28 | + ", isRead='" + isRead + '\'' + | |
29 | + ", isRecall='" + isRecall + '\'' + | |
30 | + ", intime='" + intime + '\'' + | |
31 | + ", type='" + type + '\'' + | |
32 | + '}'; | |
33 | + } | |
34 | +} | ... | ... |
... | ... | @@ -0,0 +1,31 @@ |
1 | +package com.shunzhi.parent.contract.leavermessage; | |
2 | + | |
3 | +import com.google.gson.JsonObject; | |
4 | +import com.share.mvpsdk.base.BasePresenter; | |
5 | +import com.share.mvpsdk.base.IBaseActivity; | |
6 | +import com.share.mvpsdk.base.IBaseModel; | |
7 | + | |
8 | +import java.util.List; | |
9 | + | |
10 | +import io.reactivex.Observable; | |
11 | + | |
12 | +public interface LeaverMessageContract { | |
13 | + | |
14 | + public abstract class MyLeaverMessagePresenter extends BasePresenter<ILeaverMessageModel,ILeverMessageView>{ | |
15 | + | |
16 | + public abstract void GetLeaveMessageList(String puserid,String suserid); | |
17 | + | |
18 | + } | |
19 | + | |
20 | + interface ILeaverMessageModel extends IBaseModel { | |
21 | + | |
22 | + Observable<JsonObject> GetLeaveMessageList(String puserid, String suserid); | |
23 | + | |
24 | + } | |
25 | + | |
26 | + interface ILeverMessageView extends IBaseActivity{ | |
27 | + | |
28 | + abstract void ShowLeaverMessageList(List<LeaverMessage> leaverMessageList); | |
29 | + | |
30 | + } | |
31 | +} | ... | ... |
... | ... | @@ -0,0 +1,25 @@ |
1 | +package com.shunzhi.parent.model.leavermessage; | |
2 | + | |
3 | + | |
4 | +import com.google.gson.JsonObject; | |
5 | +import com.share.mvpsdk.helper.RetrofitCreateHelper; | |
6 | +import com.share.mvpsdk.helper.RxHelper; | |
7 | +import com.shunzhi.parent.AppConfig; | |
8 | +import com.shunzhi.parent.api.GetLeaveMessageListAPI; | |
9 | +import com.shunzhi.parent.contract.leavermessage.LeaverMessageContract; | |
10 | + | |
11 | +import io.reactivex.Observable; | |
12 | + | |
13 | +public class LeaverMessageModel implements LeaverMessageContract.ILeaverMessageModel{ | |
14 | + | |
15 | + | |
16 | + @Override | |
17 | + public Observable GetLeaveMessageList(String puserid, String suserid) { | |
18 | + return RetrofitCreateHelper.getInstance().createApi(GetLeaveMessageListAPI.class, AppConfig.BASE_URL) | |
19 | + .GetLeaveMessageList(puserid,suserid).compose(RxHelper.<JsonObject>rxSchedulerHelper()); | |
20 | + } | |
21 | + | |
22 | + public static LeaverMessageContract.ILeaverMessageModel newInstance() { | |
23 | + return new LeaverMessageModel(); | |
24 | + } | |
25 | +} | ... | ... |
... | ... | @@ -0,0 +1,26 @@ |
1 | +package com.shunzhi.parent.presenter.leavermessage; | |
2 | + | |
3 | +import com.share.mvpsdk.base.BasePresenter; | |
4 | +import com.shunzhi.parent.contract.leavermessage.LeaverMessageContract; | |
5 | +import com.shunzhi.parent.model.leavermessage.LeaverMessageModel; | |
6 | + | |
7 | +public class LeaverMessagePresenter extends LeaverMessageContract.MyLeaverMessagePresenter{ | |
8 | + @Override | |
9 | + public LeaverMessageContract.ILeaverMessageModel getModel() { | |
10 | + return LeaverMessageModel.newInstance(); | |
11 | + } | |
12 | + | |
13 | + @Override | |
14 | + public void onStart() { | |
15 | + | |
16 | + } | |
17 | + | |
18 | + @Override | |
19 | + public void GetLeaveMessageList(String puserid, String suserid) { | |
20 | + | |
21 | + } | |
22 | + | |
23 | + public static BasePresenter newInstance() { | |
24 | + return new LeaverMessagePresenter(); | |
25 | + } | |
26 | +} | ... | ... |
... | ... | @@ -0,0 +1,116 @@ |
1 | +package com.shunzhi.parent.ui.activity.chartroom; | |
2 | + | |
3 | +import android.content.Intent; | |
4 | +import android.os.Bundle; | |
5 | +import android.support.v4.app.Fragment; | |
6 | +import android.support.v4.app.FragmentActivity; | |
7 | +import android.support.v4.app.FragmentManager; | |
8 | +import android.support.v4.app.FragmentPagerAdapter; | |
9 | +import android.support.v4.view.ViewPager; | |
10 | +import android.support.v4.view.ViewPager.OnPageChangeListener; | |
11 | +import android.widget.TextView; | |
12 | + | |
13 | + | |
14 | +import com.shunzhi.parent.R; | |
15 | +import com.shunzhi.parent.ui.activity.chartroom.fragment.ImageViewFragment; | |
16 | + | |
17 | +import java.util.ArrayList; | |
18 | +import java.util.List; | |
19 | + | |
20 | +public class ImageViewActivity extends FragmentActivity { | |
21 | + private ArrayList<String> imageList; | |
22 | + private List<Fragment> fragList; | |
23 | + private ViewPager imageVp; | |
24 | + private TextView currentTv; | |
25 | + private TextView totalTv; | |
26 | + private int currentPage; | |
27 | + | |
28 | + @Override | |
29 | + protected void onCreate(Bundle savedInstanceState) { | |
30 | + super.onCreate(savedInstanceState); | |
31 | + Intent intent = getIntent(); | |
32 | + Bundle bundle = intent.getExtras(); | |
33 | + if (bundle != null) { | |
34 | + if (bundle.containsKey("images")) { | |
35 | + imageList = bundle.getStringArrayList("images"); | |
36 | + } | |
37 | + if (bundle.containsKey("clickedIndex")) { | |
38 | + currentPage = bundle.getInt("clickedIndex"); | |
39 | + } | |
40 | + } | |
41 | + setContentView(R.layout.activity_images_view); | |
42 | + findView(); | |
43 | + init(); | |
44 | + } | |
45 | + | |
46 | + private void init() { | |
47 | + totalTv.setText("/" + imageList.size()); | |
48 | + fragList = new ArrayList<Fragment>(); | |
49 | + for (int i = 0; i < imageList.size(); i++) { | |
50 | + ImageViewFragment imageVF = new ImageViewFragment(); | |
51 | + imageVF.setImageUrl(imageList.get(i)); | |
52 | + fragList.add(imageVF); | |
53 | + } | |
54 | + // 类似缓存 | |
55 | + imageVp.setOffscreenPageLimit(imageList.size()); | |
56 | + imageVp.setAdapter(new ImageViewFPAdapter(getSupportFragmentManager())); | |
57 | + imageVp.setOnPageChangeListener(new OnPageChangeListener() { | |
58 | + | |
59 | + @Override | |
60 | + public void onPageSelected(int index) { | |
61 | + currentPage = index; | |
62 | + currentTv.setText((index + 1) + ""); | |
63 | + fragList.get(currentPage).onPause(); // 调用切换前Fargment的onPause() | |
64 | + if (fragList.get(index).isAdded()) { | |
65 | + fragList.get(index).onResume(); // 调用切换后Fargment的onResume() | |
66 | + } | |
67 | + } | |
68 | + | |
69 | + @Override | |
70 | + public void onPageScrolled(int arg0, float arg1, int arg2) { | |
71 | + | |
72 | + } | |
73 | + | |
74 | + @Override | |
75 | + public void onPageScrollStateChanged(int arg0) { | |
76 | + | |
77 | + } | |
78 | + }); | |
79 | + imageVp.setCurrentItem(currentPage); | |
80 | + currentTv.setText((currentPage + 1) + ""); | |
81 | + } | |
82 | + | |
83 | + protected void findView() { | |
84 | + imageVp = (ViewPager) findViewById(R.id.images_vp); | |
85 | + currentTv = (TextView) findViewById(R.id.imageView_current_tv); | |
86 | + totalTv = (TextView) findViewById(R.id.imageView_total_tv); | |
87 | + } | |
88 | + | |
89 | + class ImageViewFPAdapter extends FragmentPagerAdapter { | |
90 | + protected FragmentManager fm; | |
91 | + | |
92 | + public ImageViewFPAdapter(FragmentManager fm) { | |
93 | + super(fm); | |
94 | + this.fm = fm; | |
95 | + } | |
96 | + | |
97 | + @Override | |
98 | + public Fragment getItem(int arg0) { | |
99 | + return fragList.get(arg0); | |
100 | + } | |
101 | + | |
102 | + @Override | |
103 | + public int getCount() { | |
104 | + return fragList.size(); | |
105 | + } | |
106 | + } | |
107 | + | |
108 | + @Override | |
109 | + protected void onDestroy() { | |
110 | + if (fragList.size() > 0) { | |
111 | + for (Fragment fragment : fragList) | |
112 | + fragment.onDestroy(); | |
113 | + } | |
114 | + super.onDestroy(); | |
115 | + } | |
116 | +} | ... | ... |
... | ... | @@ -0,0 +1,442 @@ |
1 | +package com.shunzhi.parent.ui.activity.chartroom; | |
2 | + | |
3 | +import android.graphics.Rect; | |
4 | +import android.os.Bundle; | |
5 | +import android.os.Handler; | |
6 | +import android.os.Message; | |
7 | +import android.support.v7.widget.LinearLayoutManager; | |
8 | +import android.support.v7.widget.RecyclerView; | |
9 | +import android.view.View; | |
10 | +import android.view.ViewTreeObserver; | |
11 | + | |
12 | +import com.shunzhi.mychartlibrary.BaseActivity; | |
13 | +import com.shunzhi.mychartlibrary.db.ChatMessageBean; | |
14 | +import com.shunzhi.parent.ui.activity.chartroom.adapter.ChatListViewAdapter; | |
15 | +import com.shunzhi.parent.ui.activity.chartroom.adapter.ChatRecyclerAdapter; | |
16 | +import com.shunzhi.mychartlibrary.animator.SlideInOutBottomItemAnimator; | |
17 | +import com.shunzhi.mychartlibrary.common.ChatConst; | |
18 | +import com.shunzhi.mychartlibrary.utils.KeyBoardUtils; | |
19 | +import com.shunzhi.mychartlibrary.widget.AudioRecordButton; | |
20 | +import com.shunzhi.mychartlibrary.widget.pulltorefresh.PullToRefreshRecyclerView; | |
21 | +import com.shunzhi.mychartlibrary.widget.pulltorefresh.WrapContentLinearLayoutManager; | |
22 | +import com.shunzhi.mychartlibrary.widget.pulltorefresh.base.PullToRefreshView; | |
23 | + | |
24 | +import java.lang.ref.WeakReference; | |
25 | + | |
26 | +public class RecyclerViewChatActivity extends BaseActivity { | |
27 | + private PullToRefreshRecyclerView myList; | |
28 | + private ChatRecyclerAdapter tbAdapter; | |
29 | + private SendMessageHandler sendMessageHandler; | |
30 | + private WrapContentLinearLayoutManager wcLinearLayoutManger; | |
31 | + | |
32 | + @Override | |
33 | + protected void onCreate(Bundle savedInstanceState) { | |
34 | + super.onCreate(savedInstanceState); | |
35 | + } | |
36 | + | |
37 | + @Override | |
38 | + protected void findView() { | |
39 | + super.findView(); | |
40 | + pullList.setSlideView(new PullToRefreshView(this).getSlideView(PullToRefreshView.RECYCLERVIEW)); | |
41 | + myList = (PullToRefreshRecyclerView) pullList.returnMylist(); | |
42 | + } | |
43 | + | |
44 | + @Override | |
45 | + protected void onResume() { | |
46 | + // TODO Auto-generated method stub | |
47 | + super.onResume(); | |
48 | + } | |
49 | + | |
50 | + @Override | |
51 | + protected void onDestroy() { | |
52 | + tblist.clear(); | |
53 | + tbAdapter.notifyDataSetChanged(); | |
54 | + myList.setAdapter(null); | |
55 | + sendMessageHandler.removeCallbacksAndMessages(null); | |
56 | + super.onDestroy(); | |
57 | + } | |
58 | + | |
59 | + @Override | |
60 | + protected void init() { | |
61 | + setTitle(getIntent().getStringExtra("childName")); | |
62 | + tbAdapter = new ChatRecyclerAdapter(this, tblist,getIntent().getStringExtra("childPhoto")); | |
63 | + wcLinearLayoutManger = new WrapContentLinearLayoutManager(this, LinearLayoutManager.VERTICAL, false); | |
64 | + myList.setLayoutManager(wcLinearLayoutManger); | |
65 | + myList.setItemAnimator(new SlideInOutBottomItemAnimator(myList)); | |
66 | + myList.setAdapter(tbAdapter); | |
67 | + sendMessageHandler = new SendMessageHandler(this); | |
68 | + tbAdapter.isPicRefresh = true; | |
69 | + tbAdapter.notifyDataSetChanged(); | |
70 | + tbAdapter.setSendErrorListener(new ChatRecyclerAdapter.SendErrorListener() { | |
71 | + | |
72 | + @Override | |
73 | + public void onClick(int position) { | |
74 | + // TODO Auto-generated method stub | |
75 | + ChatMessageBean tbub = tblist.get(position); | |
76 | + if (tbub.getType() == ChatRecyclerAdapter.TO_USER_VOICE) { | |
77 | + sendVoice(tbub.getUserVoiceTime(), tbub.getUserVoicePath()); | |
78 | + tblist.remove(position); | |
79 | + } else if (tbub.getType() == ChatRecyclerAdapter.TO_USER_IMG) { | |
80 | + sendImage(tbub.getImageLocal()); | |
81 | + tblist.remove(position); | |
82 | + } | |
83 | + } | |
84 | + | |
85 | + }); | |
86 | + tbAdapter.setVoiceIsReadListener(new ChatRecyclerAdapter.VoiceIsRead() { | |
87 | + | |
88 | + @Override | |
89 | + public void voiceOnClick(int position) { | |
90 | + // TODO Auto-generated method stub | |
91 | + for (int i = 0; i < tbAdapter.unReadPosition.size(); i++) { | |
92 | + if (tbAdapter.unReadPosition.get(i).equals(position + "")) { | |
93 | + tbAdapter.unReadPosition.remove(i); | |
94 | + break; | |
95 | + } | |
96 | + } | |
97 | + } | |
98 | + | |
99 | + }); | |
100 | + voiceBtn.setAudioFinishRecorderListener(new AudioRecordButton.AudioFinishRecorderListener() { | |
101 | + | |
102 | + @Override | |
103 | + public void onFinished(float seconds, String filePath) { | |
104 | + // TODO Auto-generated method stub | |
105 | + sendVoice(seconds, filePath); | |
106 | + } | |
107 | + | |
108 | + @Override | |
109 | + public void onStart() { | |
110 | + // TODO Auto-generated method stub | |
111 | + tbAdapter.stopPlayVoice(); | |
112 | + } | |
113 | + }); | |
114 | + myList.setOnScrollListener(new RecyclerView.OnScrollListener() { | |
115 | + | |
116 | + @Override | |
117 | + public void onScrollStateChanged(RecyclerView view, int scrollState) { | |
118 | + // TODO Auto-generated method stub | |
119 | + switch (scrollState) { | |
120 | + case RecyclerView.SCROLL_STATE_IDLE: | |
121 | + tbAdapter.handler.removeCallbacksAndMessages(null); | |
122 | + tbAdapter.setIsGif(true); | |
123 | + tbAdapter.isPicRefresh = false; | |
124 | + tbAdapter.notifyDataSetChanged(); | |
125 | + break; | |
126 | + case RecyclerView.SCROLL_STATE_DRAGGING: | |
127 | + tbAdapter.handler.removeCallbacksAndMessages(null); | |
128 | + tbAdapter.setIsGif(false); | |
129 | + tbAdapter.isPicRefresh = true; | |
130 | + reset(); | |
131 | + KeyBoardUtils.hideKeyBoard(RecyclerViewChatActivity.this, | |
132 | + mEditTextContent); | |
133 | + break; | |
134 | + default: | |
135 | + break; | |
136 | + } | |
137 | + } | |
138 | + | |
139 | + @Override | |
140 | + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { | |
141 | + super.onScrolled(recyclerView, dx, dy); | |
142 | + } | |
143 | + }); | |
144 | + controlKeyboardLayout(activityRootView, pullList); | |
145 | + super.init(); | |
146 | + } | |
147 | + | |
148 | + /** | |
149 | + * @param root 最外层布局 | |
150 | + * @param needToScrollView 要滚动的布局,就是说在键盘弹出的时候,你需要试图滚动上去的View,在键盘隐藏的时候,他又会滚动到原来的位置的布局 | |
151 | + */ | |
152 | + private void controlKeyboardLayout(final View root, final View needToScrollView) { | |
153 | + root.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { | |
154 | + | |
155 | + private Rect r = new Rect(); | |
156 | + | |
157 | + @Override | |
158 | + public void onGlobalLayout() { | |
159 | + //获取当前界面可视部分 | |
160 | + RecyclerViewChatActivity.this.getWindow().getDecorView().getWindowVisibleDisplayFrame(r); | |
161 | + //获取屏幕的高度 | |
162 | + int screenHeight = RecyclerViewChatActivity.this.getWindow().getDecorView().getRootView().getHeight(); | |
163 | + //此处就是用来获取键盘的高度的, 在键盘没有弹出的时候 此高度为0 键盘弹出的时候为一个正数 | |
164 | + int heightDifference = screenHeight - r.bottom; | |
165 | + int recyclerHeight = 0; | |
166 | + if (wcLinearLayoutManger != null) { | |
167 | + recyclerHeight = wcLinearLayoutManger.getRecyclerHeight(); | |
168 | + } | |
169 | + if (heightDifference == 0 || heightDifference == bottomStatusHeight) { | |
170 | + needToScrollView.scrollTo(0, 0); | |
171 | + } else { | |
172 | + if (heightDifference < recyclerHeight) { | |
173 | + int contentHeight = wcLinearLayoutManger == null ? 0 : wcLinearLayoutManger.getHeight(); | |
174 | + if (recyclerHeight < contentHeight) { | |
175 | + listSlideHeight = heightDifference - (contentHeight - recyclerHeight); | |
176 | + needToScrollView.scrollTo(0, listSlideHeight); | |
177 | + } else { | |
178 | + listSlideHeight = heightDifference; | |
179 | + needToScrollView.scrollTo(0, listSlideHeight); | |
180 | + } | |
181 | + } else { | |
182 | + listSlideHeight = 0; | |
183 | + } | |
184 | + } | |
185 | + } | |
186 | + }); | |
187 | + } | |
188 | + | |
189 | + @Override | |
190 | + protected void loadRecords() { | |
191 | + isDown = true; | |
192 | + if (pagelist != null) { | |
193 | + pagelist.clear(); | |
194 | + } | |
195 | + pagelist = mChatDbManager.loadPages(page, number); | |
196 | + position = pagelist.size(); | |
197 | + if (pagelist.size() != 0) { | |
198 | + pagelist.addAll(tblist); | |
199 | + tblist.clear(); | |
200 | + tblist.addAll(pagelist); | |
201 | + if (imageList != null) { | |
202 | + imageList.clear(); | |
203 | + } | |
204 | + if (imagePosition != null) { | |
205 | + imagePosition.clear(); | |
206 | + } | |
207 | + int key = 0; | |
208 | + int position = 0; | |
209 | + for (ChatMessageBean cmb : tblist) { | |
210 | + if (cmb.getType() == ChatListViewAdapter.FROM_USER_IMG || cmb.getType() == ChatListViewAdapter.TO_USER_IMG) { | |
211 | + imageList.add(cmb.getImageLocal()); | |
212 | + imagePosition.put(key, position); | |
213 | + position++; | |
214 | + } | |
215 | + key++; | |
216 | + } | |
217 | + tbAdapter.setImageList(imageList); | |
218 | + tbAdapter.setImagePosition(imagePosition); | |
219 | + sendMessageHandler.sendEmptyMessage(PULL_TO_REFRESH_DOWN); | |
220 | + if (page == 0) { | |
221 | + pullList.refreshComplete(); | |
222 | + pullList.setPullGone(); | |
223 | + } else { | |
224 | + page--; | |
225 | + } | |
226 | + } else { | |
227 | + if (page == 0) { | |
228 | + pullList.refreshComplete(); | |
229 | + pullList.setPullGone(); | |
230 | + } | |
231 | + } | |
232 | + } | |
233 | + | |
234 | + static class SendMessageHandler extends Handler { | |
235 | + WeakReference<RecyclerViewChatActivity> mActivity; | |
236 | + | |
237 | + SendMessageHandler(RecyclerViewChatActivity activity) { | |
238 | + mActivity = new WeakReference<RecyclerViewChatActivity>(activity); | |
239 | + } | |
240 | + | |
241 | + @Override | |
242 | + public void handleMessage(Message msg) { | |
243 | + // TODO Auto-generated method stub | |
244 | + RecyclerViewChatActivity theActivity = mActivity.get(); | |
245 | + if (theActivity != null) { | |
246 | + switch (msg.what) { | |
247 | + case REFRESH: | |
248 | + theActivity.tbAdapter.isPicRefresh = true; | |
249 | + theActivity.tbAdapter.notifyDataSetChanged(); | |
250 | + int position = theActivity.tbAdapter.getItemCount() - 1 < 0 ? 0 : theActivity.tbAdapter.getItemCount() - 1; | |
251 | + theActivity.myList.smoothScrollToPosition(position); | |
252 | + break; | |
253 | + case SEND_OK: | |
254 | + theActivity.mEditTextContent.setText(""); | |
255 | + theActivity.tbAdapter.isPicRefresh = true; | |
256 | + theActivity.tbAdapter.notifyItemInserted(theActivity.tblist | |
257 | + .size() - 1); | |
258 | + theActivity.myList.smoothScrollToPosition(theActivity.tbAdapter.getItemCount() - 1); | |
259 | + break; | |
260 | + case RECERIVE_OK: | |
261 | + theActivity.tbAdapter.isPicRefresh = true; | |
262 | + theActivity.tbAdapter.notifyItemInserted(theActivity.tblist | |
263 | + .size() - 1); | |
264 | + theActivity.myList.smoothScrollToPosition(theActivity.tbAdapter.getItemCount() - 1); | |
265 | + break; | |
266 | + case PULL_TO_REFRESH_DOWN: | |
267 | + theActivity.pullList.refreshComplete(); | |
268 | + theActivity.tbAdapter.notifyDataSetChanged(); | |
269 | + theActivity.myList.smoothScrollToPosition(theActivity.position - 1); | |
270 | + theActivity.isDown = false; | |
271 | + break; | |
272 | + default: | |
273 | + break; | |
274 | + } | |
275 | + } | |
276 | + } | |
277 | + | |
278 | + } | |
279 | + | |
280 | + /** | |
281 | + * 发送文字 | |
282 | + */ | |
283 | + @Override | |
284 | + protected void sendMessage() { | |
285 | + new Thread(new Runnable() { | |
286 | + @Override | |
287 | + public void run() { | |
288 | + String content = mEditTextContent.getText().toString(); | |
289 | + tblist.add(getTbub(userName, ChatListViewAdapter.TO_USER_MSG, content, null, null, | |
290 | + null, null, null, 0f, ChatConst.COMPLETED)); | |
291 | + sendMessageHandler.sendEmptyMessage(SEND_OK); | |
292 | + RecyclerViewChatActivity.this.content = content; | |
293 | + receriveHandler.sendEmptyMessageDelayed(0, 1000); | |
294 | + } | |
295 | + }).start(); | |
296 | + } | |
297 | + | |
298 | + /** | |
299 | + * 接收文字 | |
300 | + */ | |
301 | + String content = ""; | |
302 | + | |
303 | + private void receriveMsgText(final String content) { | |
304 | + new Thread(new Runnable() { | |
305 | + @Override | |
306 | + public void run() { | |
307 | + String message = "回复:" + content; | |
308 | + ChatMessageBean tbub = new ChatMessageBean(); | |
309 | + tbub.setUserName(userName); | |
310 | + String time = returnTime(); | |
311 | + tbub.setUserContent(message); | |
312 | + tbub.setTime(time); | |
313 | + tbub.setType(ChatListViewAdapter.FROM_USER_MSG); | |
314 | + tblist.add(tbub); | |
315 | + sendMessageHandler.sendEmptyMessage(RECERIVE_OK); | |
316 | + mChatDbManager.insert(tbub); | |
317 | + } | |
318 | + }).start(); | |
319 | + } | |
320 | + | |
321 | + /** | |
322 | + * 发送图片 | |
323 | + */ | |
324 | + int i = 0; | |
325 | + | |
326 | + @Override | |
327 | + protected void sendImage(final String filePath) { | |
328 | + new Thread(new Runnable() { | |
329 | + @Override | |
330 | + public void run() { | |
331 | + if (i == 0) { | |
332 | + tblist.add(getTbub(userName, ChatListViewAdapter.TO_USER_IMG, null, null, null, filePath, null, null, | |
333 | + 0f, ChatConst.SENDING)); | |
334 | + } else if (i == 1) { | |
335 | + tblist.add(getTbub(userName, ChatListViewAdapter.TO_USER_IMG, null, null, null, filePath, null, null, | |
336 | + 0f, ChatConst.SENDERROR)); | |
337 | + } else if (i == 2) { | |
338 | + tblist.add(getTbub(userName, ChatListViewAdapter.TO_USER_IMG, null, null, null, filePath, null, null, | |
339 | + 0f, ChatConst.COMPLETED)); | |
340 | + i = -1; | |
341 | + } | |
342 | + imageList.add(tblist.get(tblist.size() - 1).getImageLocal()); | |
343 | + imagePosition.put(tblist.size() - 1, imageList.size() - 1); | |
344 | + sendMessageHandler.sendEmptyMessage(SEND_OK); | |
345 | + RecyclerViewChatActivity.this.filePath = filePath; | |
346 | + receriveHandler.sendEmptyMessageDelayed(1, 3000); | |
347 | + i++; | |
348 | + } | |
349 | + }).start(); | |
350 | + } | |
351 | + | |
352 | + /** | |
353 | + * 接收图片 | |
354 | + */ | |
355 | + String filePath = ""; | |
356 | + | |
357 | + private void receriveImageText(final String filePath) { | |
358 | + new Thread(new Runnable() { | |
359 | + @Override | |
360 | + public void run() { | |
361 | + ChatMessageBean tbub = new ChatMessageBean(); | |
362 | + tbub.setUserName(userName); | |
363 | + String time = returnTime(); | |
364 | + tbub.setTime(time); | |
365 | + tbub.setImageLocal(filePath); | |
366 | + tbub.setType(ChatListViewAdapter.FROM_USER_IMG); | |
367 | + tblist.add(tbub); | |
368 | + imageList.add(tblist.get(tblist.size() - 1).getImageLocal()); | |
369 | + imagePosition.put(tblist.size() - 1, imageList.size() - 1); | |
370 | + sendMessageHandler.sendEmptyMessage(RECERIVE_OK); | |
371 | + mChatDbManager.insert(tbub); | |
372 | + } | |
373 | + }).start(); | |
374 | + } | |
375 | + | |
376 | + /** | |
377 | + * 发送语音 | |
378 | + */ | |
379 | + @Override | |
380 | + protected void sendVoice(final float seconds, final String filePath) { | |
381 | + new Thread(new Runnable() { | |
382 | + @Override | |
383 | + public void run() { | |
384 | + tblist.add(getTbub(userName, ChatListViewAdapter.TO_USER_VOICE, null, null, null, null, filePath, | |
385 | + null, seconds, ChatConst.SENDING)); | |
386 | + sendMessageHandler.sendEmptyMessage(SEND_OK); | |
387 | + RecyclerViewChatActivity.this.seconds = seconds; | |
388 | + voiceFilePath = filePath; | |
389 | + receriveHandler.sendEmptyMessageDelayed(2, 3000); | |
390 | + } | |
391 | + }).start(); | |
392 | + } | |
393 | + | |
394 | + /** | |
395 | + * 接收语音 | |
396 | + */ | |
397 | + float seconds = 0.0f; | |
398 | + String voiceFilePath = ""; | |
399 | + | |
400 | + private void receriveVoiceText(final float seconds, final String filePath) { | |
401 | + new Thread(new Runnable() { | |
402 | + @Override | |
403 | + public void run() { | |
404 | + ChatMessageBean tbub = new ChatMessageBean(); | |
405 | + tbub.setUserName(userName); | |
406 | + String time = returnTime(); | |
407 | + tbub.setTime(time); | |
408 | + tbub.setUserVoiceTime(seconds); | |
409 | + tbub.setUserVoicePath(filePath); | |
410 | + tbAdapter.unReadPosition.add(tblist.size() + ""); | |
411 | + tbub.setType(ChatListViewAdapter.FROM_USER_VOICE); | |
412 | + tblist.add(tbub); | |
413 | + sendMessageHandler.sendEmptyMessage(RECERIVE_OK); | |
414 | + mChatDbManager.insert(tbub); | |
415 | + } | |
416 | + }).start(); | |
417 | + } | |
418 | + | |
419 | + /** | |
420 | + * 为了模拟接收延迟 | |
421 | + */ | |
422 | + private Handler receriveHandler = new Handler() { | |
423 | + @Override | |
424 | + public void handleMessage(Message msg) { | |
425 | + super.handleMessage(msg); | |
426 | + switch (msg.what) { | |
427 | + case 0: | |
428 | + receriveMsgText(content); | |
429 | + break; | |
430 | + case 1: | |
431 | + receriveImageText(filePath); | |
432 | + break; | |
433 | + case 2: | |
434 | + receriveVoiceText(seconds, voiceFilePath); | |
435 | + break; | |
436 | + default: | |
437 | + break; | |
438 | + } | |
439 | + } | |
440 | + }; | |
441 | + | |
442 | +} | ... | ... |
... | ... | @@ -0,0 +1,826 @@ |
1 | +package com.shunzhi.parent.ui.activity.chartroom.adapter; | |
2 | + | |
3 | +import android.annotation.SuppressLint; | |
4 | +import android.app.Activity; | |
5 | +import android.content.Context; | |
6 | +import android.content.Intent; | |
7 | +import android.graphics.drawable.AnimationDrawable; | |
8 | +import android.media.MediaPlayer; | |
9 | +import android.os.Handler; | |
10 | +import android.os.Message; | |
11 | +import android.util.DisplayMetrics; | |
12 | +import android.view.LayoutInflater; | |
13 | +import android.view.View; | |
14 | +import android.view.ViewGroup; | |
15 | +import android.view.WindowManager; | |
16 | +import android.view.animation.Animation; | |
17 | +import android.view.animation.AnimationUtils; | |
18 | +import android.view.animation.LinearInterpolator; | |
19 | +import android.widget.BaseAdapter; | |
20 | +import android.widget.FrameLayout; | |
21 | +import android.widget.ImageView; | |
22 | +import android.widget.LinearLayout; | |
23 | +import android.widget.TextView; | |
24 | + | |
25 | + | |
26 | +import com.shunzhi.mychartlibrary.db.ChatMessageBean; | |
27 | +import com.shunzhi.parent.R; | |
28 | +import com.shunzhi.parent.ui.activity.chartroom.ImageViewActivity; | |
29 | +import com.shunzhi.mychartlibrary.common.ChatConst; | |
30 | +import com.shunzhi.mychartlibrary.utils.FileSaveUtil; | |
31 | +import com.shunzhi.mychartlibrary.utils.ImageCheckoutUtil; | |
32 | +import com.shunzhi.mychartlibrary.widget.BubbleImageView; | |
33 | +import com.shunzhi.mychartlibrary.widget.GifTextView; | |
34 | +import com.shunzhi.mychartlibrary.widget.MediaManager; | |
35 | + | |
36 | +import java.io.File; | |
37 | +import java.lang.ref.WeakReference; | |
38 | +import java.math.BigDecimal; | |
39 | +import java.text.DateFormat; | |
40 | +import java.text.SimpleDateFormat; | |
41 | +import java.util.ArrayList; | |
42 | +import java.util.HashMap; | |
43 | +import java.util.List; | |
44 | + | |
45 | +/** | |
46 | + * Created by Mao Jiqing on 2016/9/28. | |
47 | + */ | |
48 | +public class ChatListViewAdapter extends BaseAdapter { | |
49 | + private Context context; | |
50 | + private List<ChatMessageBean> userList = new ArrayList<ChatMessageBean>(); | |
51 | + private ArrayList<String> imageList = new ArrayList<String>(); | |
52 | + private HashMap<Integer,Integer> imagePosition = new HashMap<Integer,Integer>(); | |
53 | + public static final int FROM_USER_MSG = 0;//接收消息类型 | |
54 | + public static final int TO_USER_MSG = 1;//发送消息类型 | |
55 | + public static final int FROM_USER_IMG = 2;//接收消息类型 | |
56 | + public static final int TO_USER_IMG = 3;//发送消息类型 | |
57 | + public static final int FROM_USER_VOICE = 4;//接收消息类型 | |
58 | + public static final int TO_USER_VOICE = 5;//发送消息类型 | |
59 | + private int mMinItemWith;// 设置对话框的最大宽度和最小宽度 | |
60 | + private int mMaxItemWith; | |
61 | + public MyHandler handler; | |
62 | + private Animation an; | |
63 | + private SendErrorListener sendErrorListener; | |
64 | + private VoiceIsRead voiceIsRead; | |
65 | + public List<String> unReadPosition = new ArrayList<String>(); | |
66 | + private int voicePlayPosition = -1; | |
67 | + private LayoutInflater mLayoutInflater; | |
68 | + private boolean isGif = true; | |
69 | + public boolean isPicRefresh = true; | |
70 | + | |
71 | + public interface SendErrorListener { | |
72 | + public void onClick(int position); | |
73 | + } | |
74 | + | |
75 | + public void setSendErrorListener(SendErrorListener sendErrorListener) { | |
76 | + this.sendErrorListener = sendErrorListener; | |
77 | + } | |
78 | + | |
79 | + public interface VoiceIsRead { | |
80 | + public void voiceOnClick(int position); | |
81 | + } | |
82 | + | |
83 | + public void setVoiceIsReadListener(VoiceIsRead voiceIsRead) { | |
84 | + this.voiceIsRead = voiceIsRead; | |
85 | + } | |
86 | + | |
87 | + public ChatListViewAdapter(Context context) { | |
88 | + this.context = context; | |
89 | + mLayoutInflater = LayoutInflater.from(context); | |
90 | + // 获取系统宽度 | |
91 | + WindowManager wManager = (WindowManager) context | |
92 | + .getSystemService(Context.WINDOW_SERVICE); | |
93 | + DisplayMetrics outMetrics = new DisplayMetrics(); | |
94 | + wManager.getDefaultDisplay().getMetrics(outMetrics); | |
95 | + mMaxItemWith = (int) (outMetrics.widthPixels * 0.5f); | |
96 | + mMinItemWith = (int) (outMetrics.widthPixels * 0.15f); | |
97 | + handler = new MyHandler(this); | |
98 | + } | |
99 | + | |
100 | + public static class MyHandler extends Handler { | |
101 | + private final WeakReference<ChatListViewAdapter> mTbAdapter; | |
102 | + | |
103 | + public MyHandler(ChatListViewAdapter tbAdapter) { | |
104 | + mTbAdapter = new WeakReference<ChatListViewAdapter>(tbAdapter); | |
105 | + } | |
106 | + | |
107 | + @Override | |
108 | + public void handleMessage(Message msg) { | |
109 | + ChatListViewAdapter tbAdapter = mTbAdapter.get(); | |
110 | + | |
111 | + if (tbAdapter != null) { | |
112 | + } | |
113 | + } | |
114 | + } | |
115 | + | |
116 | + public void setIsGif(boolean isGif) { | |
117 | + this.isGif = isGif; | |
118 | + } | |
119 | + | |
120 | + public void setUserList(List<ChatMessageBean> userList) { | |
121 | + this.userList = userList; | |
122 | + } | |
123 | + | |
124 | + public void setImageList(ArrayList<String> imageList) { | |
125 | + this.imageList = imageList; | |
126 | + } | |
127 | + public void setImagePosition(HashMap<Integer,Integer> imagePosition) { | |
128 | + this.imagePosition = imagePosition; | |
129 | + } | |
130 | + | |
131 | + @Override | |
132 | + public int getCount() { | |
133 | + return userList.size(); | |
134 | + } | |
135 | + | |
136 | + @Override | |
137 | + public Object getItem(int i) { | |
138 | + return userList.get(i); | |
139 | + } | |
140 | + | |
141 | + @Override | |
142 | + public long getItemId(int i) { | |
143 | + return i; | |
144 | + } | |
145 | + | |
146 | + @Override | |
147 | + public int getItemViewType(int position) { | |
148 | + // TODO Auto-generated method stub | |
149 | + return userList.get(position).getType(); | |
150 | + } | |
151 | + | |
152 | + @Override | |
153 | + public int getViewTypeCount() { | |
154 | + // TODO Auto-generated method stub | |
155 | + return 6; | |
156 | + } | |
157 | + | |
158 | + @SuppressLint("InflateParams") | |
159 | + @Override | |
160 | + public View getView(int i, View view, ViewGroup viewGroup) { | |
161 | + ChatMessageBean tbub = userList.get(i); | |
162 | + switch (getItemViewType(i)) { | |
163 | + case FROM_USER_MSG: | |
164 | + FromUserMsgViewHolder holder; | |
165 | + if (view == null) { | |
166 | + holder = new FromUserMsgViewHolder(); | |
167 | + view = mLayoutInflater.inflate(R.layout.layout_msgfrom_list_item, null); | |
168 | + holder.headicon = (ImageView) view | |
169 | + .findViewById(R.id.tb_other_user_icon); | |
170 | + holder.chat_time = (TextView) view.findViewById(R.id.chat_time); | |
171 | + holder.content = (GifTextView) view.findViewById(R.id.content); | |
172 | + view.setTag(holder); | |
173 | + } else { | |
174 | + holder = (FromUserMsgViewHolder) view.getTag(); | |
175 | + } | |
176 | + fromMsgUserLayout((FromUserMsgViewHolder) holder, tbub, i); | |
177 | + break; | |
178 | + case FROM_USER_IMG: | |
179 | + FromUserImageViewHolder holder1; | |
180 | + if (view == null) { | |
181 | + holder1 = new FromUserImageViewHolder(); | |
182 | + view = mLayoutInflater.inflate(R.layout.layout_imagefrom_list_item, null); | |
183 | + holder1.headicon = (ImageView) view | |
184 | + .findViewById(R.id.tb_other_user_icon); | |
185 | + holder1.chat_time = (TextView) view.findViewById(R.id.chat_time); | |
186 | + holder1.image_Msg = (BubbleImageView) view | |
187 | + .findViewById(R.id.image_message); | |
188 | + view.setTag(holder1); | |
189 | + } else { | |
190 | + holder1 = (FromUserImageViewHolder) view.getTag(); | |
191 | + } | |
192 | + fromImgUserLayout((FromUserImageViewHolder) holder1, tbub, i); | |
193 | + break; | |
194 | + case FROM_USER_VOICE: | |
195 | + FromUserVoiceViewHolder holder2; | |
196 | + if (view == null) { | |
197 | + holder2 = new FromUserVoiceViewHolder(); | |
198 | + view = mLayoutInflater.inflate(R.layout.layout_voicefrom_list_item, null); | |
199 | + holder2.headicon = (ImageView) view | |
200 | + .findViewById(R.id.tb_other_user_icon); | |
201 | + holder2.chat_time = (TextView) view.findViewById(R.id.chat_time); | |
202 | + holder2.voice_group = (LinearLayout) view | |
203 | + .findViewById(R.id.voice_group); | |
204 | + holder2.voice_time = (TextView) view | |
205 | + .findViewById(R.id.voice_time); | |
206 | + holder2.receiver_voice_unread = (View) view | |
207 | + .findViewById(R.id.receiver_voice_unread); | |
208 | + holder2.voice_image = (FrameLayout) view | |
209 | + .findViewById(R.id.voice_receiver_image); | |
210 | + holder2.voice_anim = (View) view | |
211 | + .findViewById(R.id.id_receiver_recorder_anim); | |
212 | + view.setTag(holder2); | |
213 | + } else { | |
214 | + holder2 = (FromUserVoiceViewHolder) view.getTag(); | |
215 | + } | |
216 | + fromVoiceUserLayout((FromUserVoiceViewHolder) holder2, tbub, i); | |
217 | + break; | |
218 | + case TO_USER_MSG: | |
219 | + ToUserMsgViewHolder holder3; | |
220 | + if (view == null) { | |
221 | + holder3 = new ToUserMsgViewHolder(); | |
222 | + view = mLayoutInflater.inflate(R.layout.layout_msgto_list_item, null); | |
223 | + holder3.headicon = (ImageView) view | |
224 | + .findViewById(R.id.tb_my_user_icon); | |
225 | + holder3.chat_time = (TextView) view | |
226 | + .findViewById(R.id.mychat_time); | |
227 | + holder3.content = (GifTextView) view | |
228 | + .findViewById(R.id.mycontent); | |
229 | + holder3.sendFailImg = (ImageView) view | |
230 | + .findViewById(R.id.mysend_fail_img); | |
231 | + view.setTag(holder3); | |
232 | + } else { | |
233 | + holder3 = (ToUserMsgViewHolder) view.getTag(); | |
234 | + } | |
235 | + toMsgUserLayout((ToUserMsgViewHolder) holder3, tbub, i); | |
236 | + break; | |
237 | + case TO_USER_IMG: | |
238 | + ToUserImgViewHolder holder4; | |
239 | + if (view == null) { | |
240 | + holder4 = new ToUserImgViewHolder(); | |
241 | + view = mLayoutInflater.inflate(R.layout.layout_imageto_list_item, null); | |
242 | + holder4.headicon = (ImageView) view | |
243 | + .findViewById(R.id.tb_my_user_icon); | |
244 | + holder4.chat_time = (TextView) view | |
245 | + .findViewById(R.id.mychat_time); | |
246 | + holder4.sendFailImg = (ImageView) view | |
247 | + .findViewById(R.id.mysend_fail_img); | |
248 | + holder4.image_group = (LinearLayout) view | |
249 | + .findViewById(R.id.image_group); | |
250 | + holder4.image_Msg = (BubbleImageView) view | |
251 | + .findViewById(R.id.image_message); | |
252 | + view.setTag(holder4); | |
253 | + } else { | |
254 | + holder4 = (ToUserImgViewHolder) view.getTag(); | |
255 | + } | |
256 | + toImgUserLayout((ToUserImgViewHolder) holder4, tbub, i); | |
257 | + break; | |
258 | + case TO_USER_VOICE: | |
259 | + ToUserVoiceViewHolder holder5; | |
260 | + if (view == null) { | |
261 | + holder5 = new ToUserVoiceViewHolder(); | |
262 | + view = mLayoutInflater.inflate(R.layout.layout_voiceto_list_item, null); | |
263 | + holder5.headicon = (ImageView) view | |
264 | + .findViewById(R.id.tb_my_user_icon); | |
265 | + holder5.chat_time = (TextView) view | |
266 | + .findViewById(R.id.mychat_time); | |
267 | + holder5.voice_group = (LinearLayout) view | |
268 | + .findViewById(R.id.voice_group); | |
269 | + holder5.voice_time = (TextView) view | |
270 | + .findViewById(R.id.voice_time); | |
271 | + holder5.voice_image = (FrameLayout) view | |
272 | + .findViewById(R.id.voice_image); | |
273 | + holder5.voice_anim = (View) view | |
274 | + .findViewById(R.id.id_recorder_anim); | |
275 | + holder5.sendFailImg = (ImageView) view | |
276 | + .findViewById(R.id.mysend_fail_img); | |
277 | + view.setTag(holder5); | |
278 | + } else { | |
279 | + holder5 = (ToUserVoiceViewHolder) view.getTag(); | |
280 | + } | |
281 | + toVoiceUserLayout((ToUserVoiceViewHolder) holder5, tbub, i); | |
282 | + break; | |
283 | + } | |
284 | + | |
285 | + return view; | |
286 | + } | |
287 | + | |
288 | + public class FromUserMsgViewHolder { | |
289 | + public ImageView headicon; | |
290 | + public TextView chat_time; | |
291 | + public GifTextView content; | |
292 | + } | |
293 | + | |
294 | + public class FromUserImageViewHolder { | |
295 | + public ImageView headicon; | |
296 | + public TextView chat_time; | |
297 | + public BubbleImageView image_Msg; | |
298 | + } | |
299 | + | |
300 | + public class FromUserVoiceViewHolder { | |
301 | + public ImageView headicon; | |
302 | + public TextView chat_time; | |
303 | + public LinearLayout voice_group; | |
304 | + public TextView voice_time; | |
305 | + public FrameLayout voice_image; | |
306 | + public View receiver_voice_unread; | |
307 | + public View voice_anim; | |
308 | + } | |
309 | + | |
310 | + public class ToUserMsgViewHolder { | |
311 | + public ImageView headicon; | |
312 | + public TextView chat_time; | |
313 | + public GifTextView content; | |
314 | + public ImageView sendFailImg; | |
315 | + } | |
316 | + | |
317 | + public class ToUserImgViewHolder { | |
318 | + public ImageView headicon; | |
319 | + public TextView chat_time; | |
320 | + public LinearLayout image_group; | |
321 | + public BubbleImageView image_Msg; | |
322 | + public ImageView sendFailImg; | |
323 | + } | |
324 | + | |
325 | + public class ToUserVoiceViewHolder { | |
326 | + public ImageView headicon; | |
327 | + public TextView chat_time; | |
328 | + public LinearLayout voice_group; | |
329 | + public TextView voice_time; | |
330 | + public FrameLayout voice_image; | |
331 | + public View receiver_voice_unread; | |
332 | + public View voice_anim; | |
333 | + public ImageView sendFailImg; | |
334 | + } | |
335 | + | |
336 | + private void fromMsgUserLayout(final FromUserMsgViewHolder holder, final ChatMessageBean tbub, final int position) { | |
337 | + holder.headicon.setBackgroundResource(R.mipmap.tongbao_hiv); | |
338 | + /* time */ | |
339 | + if (position != 0) { | |
340 | + String showTime = getTime(tbub.getTime(), userList.get(position - 1) | |
341 | + .getTime()); | |
342 | + if (showTime != null) { | |
343 | + holder.chat_time.setVisibility(View.VISIBLE); | |
344 | + holder.chat_time.setText(showTime); | |
345 | + } else { | |
346 | + holder.chat_time.setVisibility(View.GONE); | |
347 | + } | |
348 | + } else { | |
349 | + String showTime = getTime(tbub.getTime(), null); | |
350 | + holder.chat_time.setVisibility(View.VISIBLE); | |
351 | + holder.chat_time.setText(showTime); | |
352 | + } | |
353 | + holder.content.setVisibility(View.VISIBLE); | |
354 | + holder.content.setSpanText(handler, tbub.getUserContent(), isGif); | |
355 | + } | |
356 | + | |
357 | + private void fromImgUserLayout(final FromUserImageViewHolder holder, final ChatMessageBean tbub, final int position) { | |
358 | + holder.headicon.setBackgroundResource(R.mipmap.tongbao_hiv); | |
359 | + /* time */ | |
360 | + if (position != 0) { | |
361 | + String showTime = getTime(tbub.getTime(), userList.get(position - 1) | |
362 | + .getTime()); | |
363 | + if (showTime != null) { | |
364 | + holder.chat_time.setVisibility(View.VISIBLE); | |
365 | + holder.chat_time.setText(showTime); | |
366 | + } else { | |
367 | + holder.chat_time.setVisibility(View.GONE); | |
368 | + } | |
369 | + } else { | |
370 | + String showTime = getTime(tbub.getTime(), null); | |
371 | + holder.chat_time.setVisibility(View.VISIBLE); | |
372 | + holder.chat_time.setText(showTime); | |
373 | + } | |
374 | + if (isPicRefresh) { | |
375 | +// holder.image_Msg.setImageBitmap(null); | |
376 | + final String imageSrc = tbub.getImageLocal() == null ? "" : tbub | |
377 | + .getImageLocal(); | |
378 | + final String imageUrlSrc = tbub.getImageUrl() == null ? "" : tbub | |
379 | + .getImageUrl(); | |
380 | + final String imageIconUrl = tbub.getImageIconUrl() == null ? "" | |
381 | + : tbub.getImageIconUrl(); | |
382 | + File file = new File(imageSrc); | |
383 | + final boolean hasLocal = !imageSrc.equals("") | |
384 | + && FileSaveUtil.isFileExists(file); | |
385 | + int res; | |
386 | + res = R.drawable.chatfrom_bg_focused; | |
387 | + if (hasLocal) { | |
388 | + holder.image_Msg.setLocalImageBitmap(ImageCheckoutUtil.getLoacalBitmap(imageSrc), | |
389 | + res); | |
390 | + } else { | |
391 | + holder.image_Msg.load(imageIconUrl, res, R.mipmap.cygs_cs); | |
392 | + } | |
393 | + holder.image_Msg.setOnClickListener(new View.OnClickListener() { | |
394 | + | |
395 | + @Override | |
396 | + public void onClick(View view) { | |
397 | + // TODO Auto-generated method stub | |
398 | + stopPlayVoice(); | |
399 | + Intent intent = new Intent(context, ImageViewActivity.class); | |
400 | + intent.putStringArrayListExtra("images", imageList); | |
401 | + intent.putExtra("clickedIndex", imagePosition.get(position)); | |
402 | + context.startActivity(intent); | |
403 | + } | |
404 | + | |
405 | + }); | |
406 | + } | |
407 | + | |
408 | + } | |
409 | + | |
410 | + private void fromVoiceUserLayout(final FromUserVoiceViewHolder holder, final ChatMessageBean tbub, final int position) { | |
411 | + holder.headicon.setBackgroundResource(R.mipmap.tongbao_hiv); | |
412 | + /* time */ | |
413 | + if (position != 0) { | |
414 | + String showTime = getTime(tbub.getTime(), userList.get(position - 1) | |
415 | + .getTime()); | |
416 | + if (showTime != null) { | |
417 | + holder.chat_time.setVisibility(View.VISIBLE); | |
418 | + holder.chat_time.setText(showTime); | |
419 | + } else { | |
420 | + holder.chat_time.setVisibility(View.GONE); | |
421 | + } | |
422 | + } else { | |
423 | + String showTime = getTime(tbub.getTime(), null); | |
424 | + holder.chat_time.setVisibility(View.VISIBLE); | |
425 | + holder.chat_time.setText(showTime); | |
426 | + } | |
427 | + | |
428 | + holder.voice_group.setVisibility(View.VISIBLE); | |
429 | + if (holder.receiver_voice_unread != null) | |
430 | + holder.receiver_voice_unread.setVisibility(View.GONE); | |
431 | + if (holder.receiver_voice_unread != null && unReadPosition != null) { | |
432 | + for (String unRead : unReadPosition) { | |
433 | + if (unRead.equals(position + "")) { | |
434 | + holder.receiver_voice_unread | |
435 | + .setVisibility(View.VISIBLE); | |
436 | + break; | |
437 | + } | |
438 | + } | |
439 | + } | |
440 | + AnimationDrawable drawable; | |
441 | + holder.voice_anim.setId(position); | |
442 | + if (position == voicePlayPosition) { | |
443 | + holder.voice_anim | |
444 | + .setBackgroundResource(R.mipmap.receiver_voice_node_playing003); | |
445 | + holder.voice_anim | |
446 | + .setBackgroundResource(R.drawable.voice_play_receiver); | |
447 | + drawable = (AnimationDrawable) holder.voice_anim | |
448 | + .getBackground(); | |
449 | + drawable.start(); | |
450 | + } else { | |
451 | + holder.voice_anim | |
452 | + .setBackgroundResource(R.mipmap.receiver_voice_node_playing003); | |
453 | + } | |
454 | + holder.voice_group.setOnClickListener(new View.OnClickListener() { | |
455 | + | |
456 | + @Override | |
457 | + public void onClick(View v) { | |
458 | + // TODO Auto-generated method stub | |
459 | + if (holder.receiver_voice_unread != null) | |
460 | + holder.receiver_voice_unread.setVisibility(View.GONE); | |
461 | + holder.voice_anim | |
462 | + .setBackgroundResource(R.mipmap.receiver_voice_node_playing003); | |
463 | + stopPlayVoice(); | |
464 | + voicePlayPosition = holder.voice_anim.getId(); | |
465 | + AnimationDrawable drawable; | |
466 | + holder.voice_anim | |
467 | + .setBackgroundResource(R.drawable.voice_play_receiver); | |
468 | + drawable = (AnimationDrawable) holder.voice_anim | |
469 | + .getBackground(); | |
470 | + drawable.start(); | |
471 | + String voicePath = tbub.getUserVoicePath() == null ? "" : tbub | |
472 | + .getUserVoicePath(); | |
473 | + File file = new File(voicePath); | |
474 | + if (!(!voicePath.equals("") && FileSaveUtil | |
475 | + .isFileExists(file))) { | |
476 | + voicePath = tbub.getUserVoiceUrl() == null ? "" | |
477 | + : tbub.getUserVoiceUrl(); | |
478 | + } | |
479 | + if (voiceIsRead != null) { | |
480 | + voiceIsRead.voiceOnClick(position); | |
481 | + } | |
482 | + MediaManager.playSound(voicePath, | |
483 | + new MediaPlayer.OnCompletionListener() { | |
484 | + | |
485 | + @Override | |
486 | + public void onCompletion(MediaPlayer mp) { | |
487 | + voicePlayPosition = -1; | |
488 | + holder.voice_anim | |
489 | + .setBackgroundResource(R.mipmap.receiver_voice_node_playing003); | |
490 | + } | |
491 | + }); | |
492 | + } | |
493 | + | |
494 | + }); | |
495 | + float voiceTime = tbub.getUserVoiceTime(); | |
496 | + BigDecimal b = new BigDecimal(voiceTime); | |
497 | + float f1 = b.setScale(1, BigDecimal.ROUND_HALF_UP).floatValue(); | |
498 | + holder.voice_time.setText(f1 + "\""); | |
499 | + ViewGroup.LayoutParams lParams = holder.voice_image | |
500 | + .getLayoutParams(); | |
501 | + lParams.width = (int) (mMinItemWith + mMaxItemWith / 60f | |
502 | + * tbub.getUserVoiceTime()); | |
503 | + holder.voice_image.setLayoutParams(lParams); | |
504 | + } | |
505 | + | |
506 | + private void toMsgUserLayout(final ToUserMsgViewHolder holder, final ChatMessageBean tbub, final int position) { | |
507 | + holder.headicon.setBackgroundResource(R.mipmap.grzx_tx_s); | |
508 | + holder.headicon.setImageDrawable(context.getResources() | |
509 | + .getDrawable(R.mipmap.grzx_tx_s)); | |
510 | + /* time */ | |
511 | + if (position != 0) { | |
512 | + String showTime = getTime(tbub.getTime(), userList.get(position - 1) | |
513 | + .getTime()); | |
514 | + if (showTime != null) { | |
515 | + holder.chat_time.setVisibility(View.VISIBLE); | |
516 | + holder.chat_time.setText(showTime); | |
517 | + } else { | |
518 | + holder.chat_time.setVisibility(View.GONE); | |
519 | + } | |
520 | + } else { | |
521 | + String showTime = getTime(tbub.getTime(), null); | |
522 | + holder.chat_time.setVisibility(View.VISIBLE); | |
523 | + holder.chat_time.setText(showTime); | |
524 | + } | |
525 | + | |
526 | + holder.content.setVisibility(View.VISIBLE); | |
527 | + holder.content.setSpanText(handler, tbub.getUserContent(), isGif); | |
528 | + } | |
529 | + | |
530 | + private void toImgUserLayout(final ToUserImgViewHolder holder, final ChatMessageBean tbub, final int position) { | |
531 | + holder.headicon.setBackgroundResource(R.mipmap.grzx_tx_s); | |
532 | + switch (tbub.getSendState()) { | |
533 | + case ChatConst.SENDING: | |
534 | + an = AnimationUtils.loadAnimation(context, | |
535 | + R.anim.update_loading_progressbar_anim); | |
536 | + LinearInterpolator lin = new LinearInterpolator(); | |
537 | + an.setInterpolator(lin); | |
538 | + an.setRepeatCount(-1); | |
539 | + holder.sendFailImg | |
540 | + .setBackgroundResource(R.mipmap.xsearch_loading); | |
541 | + holder.sendFailImg.startAnimation(an); | |
542 | + an.startNow(); | |
543 | + holder.sendFailImg.setVisibility(View.VISIBLE); | |
544 | + break; | |
545 | + | |
546 | + case ChatConst.COMPLETED: | |
547 | + holder.sendFailImg.clearAnimation(); | |
548 | + holder.sendFailImg.setVisibility(View.GONE); | |
549 | + break; | |
550 | + | |
551 | + case ChatConst.SENDERROR: | |
552 | + holder.sendFailImg.clearAnimation(); | |
553 | + holder.sendFailImg | |
554 | + .setBackgroundResource(R.mipmap.msg_state_fail_resend_pressed); | |
555 | + holder.sendFailImg.setVisibility(View.VISIBLE); | |
556 | + holder.sendFailImg.setOnClickListener(new View.OnClickListener() { | |
557 | + | |
558 | + @Override | |
559 | + public void onClick(View view) { | |
560 | + // TODO Auto-generated method stub | |
561 | + if (sendErrorListener != null) { | |
562 | + sendErrorListener.onClick(position); | |
563 | + } | |
564 | + } | |
565 | + | |
566 | + }); | |
567 | + break; | |
568 | + default: | |
569 | + break; | |
570 | + } | |
571 | + holder.headicon.setImageDrawable(context.getResources() | |
572 | + .getDrawable(R.mipmap.grzx_tx_s)); | |
573 | + | |
574 | + /* time */ | |
575 | + if (position != 0) { | |
576 | + String showTime = getTime(tbub.getTime(), userList.get(position - 1) | |
577 | + .getTime()); | |
578 | + if (showTime != null) { | |
579 | + holder.chat_time.setVisibility(View.VISIBLE); | |
580 | + holder.chat_time.setText(showTime); | |
581 | + } else { | |
582 | + holder.chat_time.setVisibility(View.GONE); | |
583 | + } | |
584 | + } else { | |
585 | + String showTime = getTime(tbub.getTime(), null); | |
586 | + holder.chat_time.setVisibility(View.VISIBLE); | |
587 | + holder.chat_time.setText(showTime); | |
588 | + } | |
589 | + | |
590 | + if (isPicRefresh) { | |
591 | +// holder.image_Msg.setImageBitmap(null); | |
592 | + holder.image_group.setVisibility(View.VISIBLE); | |
593 | + final String imageSrc = tbub.getImageLocal() == null ? "" : tbub | |
594 | + .getImageLocal(); | |
595 | + final String imageUrlSrc = tbub.getImageUrl() == null ? "" : tbub | |
596 | + .getImageUrl(); | |
597 | + final String imageIconUrl = tbub.getImageIconUrl() == null ? "" | |
598 | + : tbub.getImageIconUrl(); | |
599 | + File file = new File(imageSrc); | |
600 | + final boolean hasLocal = !imageSrc.equals("") | |
601 | + && FileSaveUtil.isFileExists(file); | |
602 | + int res; | |
603 | + res = R.drawable.chatto_bg_focused; | |
604 | + if (hasLocal) { | |
605 | + holder.image_Msg.setLocalImageBitmap(ImageCheckoutUtil.getLoacalBitmap(imageSrc), | |
606 | + res); | |
607 | + } else { | |
608 | + holder.image_Msg.load(imageIconUrl, res, R.mipmap.cygs_cs); | |
609 | + } | |
610 | + holder.image_Msg.setOnClickListener(new View.OnClickListener() { | |
611 | + | |
612 | + @Override | |
613 | + public void onClick(View view) { | |
614 | + // TODO Auto-generated method stub | |
615 | + stopPlayVoice(); | |
616 | + Intent intent = new Intent(context, ImageViewActivity.class); | |
617 | + intent.putStringArrayListExtra("images", imageList); | |
618 | + intent.putExtra("clickedIndex", imagePosition.get(position)); | |
619 | + context.startActivity(intent); | |
620 | + } | |
621 | + | |
622 | + }); | |
623 | + } | |
624 | + } | |
625 | + | |
626 | + private void toVoiceUserLayout(final ToUserVoiceViewHolder holder, final ChatMessageBean tbub, final int position) { | |
627 | + holder.headicon.setBackgroundResource(R.mipmap.grzx_tx_s); | |
628 | + switch (tbub.getSendState()) { | |
629 | + case ChatConst.SENDING: | |
630 | + an = AnimationUtils.loadAnimation(context, | |
631 | + R.anim.update_loading_progressbar_anim); | |
632 | + LinearInterpolator lin = new LinearInterpolator(); | |
633 | + an.setInterpolator(lin); | |
634 | + an.setRepeatCount(-1); | |
635 | + holder.sendFailImg | |
636 | + .setBackgroundResource(R.mipmap.xsearch_loading); | |
637 | + holder.sendFailImg.startAnimation(an); | |
638 | + an.startNow(); | |
639 | + holder.sendFailImg.setVisibility(View.VISIBLE); | |
640 | + break; | |
641 | + | |
642 | + case ChatConst.COMPLETED: | |
643 | + holder.sendFailImg.clearAnimation(); | |
644 | + holder.sendFailImg.setVisibility(View.GONE); | |
645 | + break; | |
646 | + | |
647 | + case ChatConst.SENDERROR: | |
648 | + holder.sendFailImg.clearAnimation(); | |
649 | + holder.sendFailImg | |
650 | + .setBackgroundResource(R.mipmap.msg_state_fail_resend_pressed); | |
651 | + holder.sendFailImg.setVisibility(View.VISIBLE); | |
652 | + holder.sendFailImg.setOnClickListener(new View.OnClickListener() { | |
653 | + | |
654 | + @Override | |
655 | + public void onClick(View view) { | |
656 | + // TODO Auto-generated method stub | |
657 | + if (sendErrorListener != null) { | |
658 | + sendErrorListener.onClick(position); | |
659 | + } | |
660 | + } | |
661 | + | |
662 | + }); | |
663 | + break; | |
664 | + default: | |
665 | + break; | |
666 | + } | |
667 | + holder.headicon.setImageDrawable(context.getResources() | |
668 | + .getDrawable(R.mipmap.grzx_tx_s)); | |
669 | + | |
670 | + /* time */ | |
671 | + if (position != 0) { | |
672 | + String showTime = getTime(tbub.getTime(), userList.get(position - 1) | |
673 | + .getTime()); | |
674 | + if (showTime != null) { | |
675 | + holder.chat_time.setVisibility(View.VISIBLE); | |
676 | + holder.chat_time.setText(showTime); | |
677 | + } else { | |
678 | + holder.chat_time.setVisibility(View.GONE); | |
679 | + } | |
680 | + } else { | |
681 | + String showTime = getTime(tbub.getTime(), null); | |
682 | + holder.chat_time.setVisibility(View.VISIBLE); | |
683 | + holder.chat_time.setText(showTime); | |
684 | + } | |
685 | + holder.voice_group.setVisibility(View.VISIBLE); | |
686 | + if (holder.receiver_voice_unread != null) | |
687 | + holder.receiver_voice_unread.setVisibility(View.GONE); | |
688 | + if (holder.receiver_voice_unread != null && unReadPosition != null) { | |
689 | + for (String unRead : unReadPosition) { | |
690 | + if (unRead.equals(position + "")) { | |
691 | + holder.receiver_voice_unread | |
692 | + .setVisibility(View.VISIBLE); | |
693 | + break; | |
694 | + } | |
695 | + } | |
696 | + } | |
697 | + AnimationDrawable drawable; | |
698 | + holder.voice_anim.setId(position); | |
699 | + if (position == voicePlayPosition) { | |
700 | + holder.voice_anim.setBackgroundResource(R.mipmap.adj); | |
701 | + holder.voice_anim | |
702 | + .setBackgroundResource(R.drawable.voice_play_send); | |
703 | + drawable = (AnimationDrawable) holder.voice_anim | |
704 | + .getBackground(); | |
705 | + drawable.start(); | |
706 | + } else { | |
707 | + holder.voice_anim.setBackgroundResource(R.mipmap.adj); | |
708 | + } | |
709 | + holder.voice_group.setOnClickListener(new View.OnClickListener() { | |
710 | + | |
711 | + @Override | |
712 | + public void onClick(View v) { | |
713 | + // TODO Auto-generated method stub | |
714 | + if (holder.receiver_voice_unread != null) | |
715 | + holder.receiver_voice_unread.setVisibility(View.GONE); | |
716 | + holder.voice_anim.setBackgroundResource(R.mipmap.adj); | |
717 | + stopPlayVoice(); | |
718 | + voicePlayPosition = holder.voice_anim.getId(); | |
719 | + AnimationDrawable drawable; | |
720 | + holder.voice_anim | |
721 | + .setBackgroundResource(R.drawable.voice_play_send); | |
722 | + drawable = (AnimationDrawable) holder.voice_anim | |
723 | + .getBackground(); | |
724 | + drawable.start(); | |
725 | + String voicePath = tbub.getUserVoiceUrl() == null ? "" | |
726 | + : tbub.getUserVoiceUrl(); | |
727 | + if (voiceIsRead != null) { | |
728 | + voiceIsRead.voiceOnClick(position); | |
729 | + } | |
730 | + MediaManager.playSound(voicePath, | |
731 | + new MediaPlayer.OnCompletionListener() { | |
732 | + | |
733 | + @Override | |
734 | + public void onCompletion(MediaPlayer mp) { | |
735 | + voicePlayPosition = -1; | |
736 | + holder.voice_anim | |
737 | + .setBackgroundResource(R.mipmap.adj); | |
738 | + } | |
739 | + }); | |
740 | + } | |
741 | + | |
742 | + }); | |
743 | + float voiceTime = tbub.getUserVoiceTime(); | |
744 | + BigDecimal b = new BigDecimal(voiceTime); | |
745 | + float f1 = b.setScale(1, BigDecimal.ROUND_HALF_UP).floatValue(); | |
746 | + holder.voice_time.setText(f1 + "\""); | |
747 | + ViewGroup.LayoutParams lParams = holder.voice_image | |
748 | + .getLayoutParams(); | |
749 | + lParams.width = (int) (mMinItemWith + mMaxItemWith / 60f | |
750 | + * tbub.getUserVoiceTime()); | |
751 | + holder.voice_image.setLayoutParams(lParams); | |
752 | + } | |
753 | + | |
754 | + @SuppressLint("SimpleDateFormat") | |
755 | + public String getTime(String time, String before) { | |
756 | + String show_time = null; | |
757 | + if (before != null) { | |
758 | + try { | |
759 | + DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); | |
760 | + java.util.Date now = df.parse(time); | |
761 | + java.util.Date date = df.parse(before); | |
762 | + long l = now.getTime() - date.getTime(); | |
763 | + long day = l / (24 * 60 * 60 * 1000); | |
764 | + long hour = (l / (60 * 60 * 1000) - day * 24); | |
765 | + long min = ((l / (60 * 1000)) - day * 24 * 60 - hour * 60); | |
766 | + if (min >= 1) { | |
767 | + show_time = time.substring(11); | |
768 | + } | |
769 | + } catch (Exception e) { | |
770 | + e.printStackTrace(); | |
771 | + } | |
772 | + } else { | |
773 | + show_time = time.substring(11); | |
774 | + } | |
775 | + String getDay = getDay(time); | |
776 | + if (show_time != null && getDay != null) | |
777 | + show_time = getDay + " " + show_time; | |
778 | + return show_time; | |
779 | + } | |
780 | + | |
781 | + @SuppressLint("SimpleDateFormat") | |
782 | + public static String returnTime() { | |
783 | + SimpleDateFormat sDateFormat = new SimpleDateFormat( | |
784 | + "yyyy-MM-dd HH:mm:ss"); | |
785 | + String date = sDateFormat.format(new java.util.Date()); | |
786 | + return date; | |
787 | + } | |
788 | + | |
789 | + @SuppressLint("SimpleDateFormat") | |
790 | + public String getDay(String time) { | |
791 | + String showDay = null; | |
792 | + String nowTime = returnTime(); | |
793 | + try { | |
794 | + DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); | |
795 | + java.util.Date now = df.parse(nowTime); | |
796 | + java.util.Date date = df.parse(time); | |
797 | + long l = now.getTime() - date.getTime(); | |
798 | + long day = l / (24 * 60 * 60 * 1000); | |
799 | + if (day >= 365) { | |
800 | + showDay = time.substring(0, 10); | |
801 | + } else if (day >= 1 && day < 365) { | |
802 | + showDay = time.substring(5, 10); | |
803 | + } | |
804 | + } catch (Exception e) { | |
805 | + e.printStackTrace(); | |
806 | + } | |
807 | + return showDay; | |
808 | + } | |
809 | + | |
810 | + public void stopPlayVoice() { | |
811 | + if (voicePlayPosition != -1) { | |
812 | + View voicePlay = (View) ((Activity) context) | |
813 | + .findViewById(voicePlayPosition); | |
814 | + if (voicePlay != null) { | |
815 | + if (getItemViewType(voicePlayPosition) == FROM_USER_VOICE) { | |
816 | + voicePlay | |
817 | + .setBackgroundResource(R.mipmap.receiver_voice_node_playing003); | |
818 | + } else { | |
819 | + voicePlay.setBackgroundResource(R.mipmap.adj); | |
820 | + } | |
821 | + } | |
822 | + MediaManager.pause(); | |
823 | + voicePlayPosition = -1; | |
824 | + } | |
825 | + } | |
826 | +} | ... | ... |
... | ... | @@ -0,0 +1,858 @@ |
1 | +package com.shunzhi.parent.ui.activity.chartroom.adapter; | |
2 | + | |
3 | +import android.annotation.SuppressLint; | |
4 | +import android.app.Activity; | |
5 | +import android.content.Context; | |
6 | +import android.content.Intent; | |
7 | +import android.graphics.Bitmap; | |
8 | +import android.graphics.BitmapFactory; | |
9 | +import android.graphics.drawable.AnimationDrawable; | |
10 | +import android.media.MediaPlayer; | |
11 | +import android.os.Handler; | |
12 | +import android.support.v7.widget.RecyclerView; | |
13 | +import android.text.TextUtils; | |
14 | +import android.util.DisplayMetrics; | |
15 | +import android.view.LayoutInflater; | |
16 | +import android.view.View; | |
17 | +import android.view.ViewGroup; | |
18 | +import android.view.WindowManager; | |
19 | +import android.view.animation.Animation; | |
20 | +import android.view.animation.AnimationUtils; | |
21 | +import android.view.animation.LinearInterpolator; | |
22 | +import android.widget.FrameLayout; | |
23 | +import android.widget.ImageView; | |
24 | +import android.widget.LinearLayout; | |
25 | +import android.widget.TextView; | |
26 | + | |
27 | +import com.bumptech.glide.Glide; | |
28 | +import com.shunzhi.mychartlibrary.db.ChatMessageBean; | |
29 | +import com.shunzhi.parent.AppConfig; | |
30 | +import com.shunzhi.parent.AppContext; | |
31 | +import com.shunzhi.parent.R; | |
32 | +import com.shunzhi.parent.ui.activity.chartroom.ImageViewActivity; | |
33 | +import com.shunzhi.mychartlibrary.common.ChatConst; | |
34 | +import com.shunzhi.mychartlibrary.utils.FileSaveUtil; | |
35 | +import com.shunzhi.mychartlibrary.widget.BubbleImageView; | |
36 | +import com.shunzhi.mychartlibrary.widget.CustomShapeTransformation; | |
37 | +import com.shunzhi.mychartlibrary.widget.GifTextView; | |
38 | +import com.shunzhi.mychartlibrary.widget.MediaManager; | |
39 | +import com.shunzhi.parent.util.GlideUtils; | |
40 | + | |
41 | +import java.io.BufferedInputStream; | |
42 | +import java.io.ByteArrayOutputStream; | |
43 | +import java.io.File; | |
44 | +import java.io.FileInputStream; | |
45 | +import java.io.FileNotFoundException; | |
46 | +import java.io.IOException; | |
47 | +import java.math.BigDecimal; | |
48 | +import java.text.DateFormat; | |
49 | +import java.text.SimpleDateFormat; | |
50 | +import java.util.ArrayList; | |
51 | +import java.util.HashMap; | |
52 | +import java.util.List; | |
53 | + | |
54 | +/** | |
55 | + * Created by Mao Jiqing on 2016/9/29. | |
56 | + */ | |
57 | +public class ChatRecyclerAdapter extends | |
58 | + RecyclerView.Adapter<RecyclerView.ViewHolder> { | |
59 | + private Context context; | |
60 | + private List<ChatMessageBean> userList = new ArrayList<ChatMessageBean>(); | |
61 | + private ArrayList<String> imageList = new ArrayList<String>(); | |
62 | + private HashMap<Integer, Integer> imagePosition = new HashMap<Integer, Integer>(); | |
63 | + public static final int FROM_USER_MSG = 0;//接收消息类型 | |
64 | + public static final int TO_USER_MSG = 1;//发送消息类型 | |
65 | + public static final int FROM_USER_IMG = 2;//接收消息类型 | |
66 | + public static final int TO_USER_IMG = 3;//发送消息类型 | |
67 | + public static final int FROM_USER_VOICE = 4;//接收消息类型 | |
68 | + public static final int TO_USER_VOICE = 5;//发送消息类型 | |
69 | + private int mMinItemWith;// 设置对话框的最大宽度和最小宽度 | |
70 | + private int mMaxItemWith; | |
71 | + public Handler handler; | |
72 | + private Animation an; | |
73 | + private SendErrorListener sendErrorListener; | |
74 | + private VoiceIsRead voiceIsRead; | |
75 | + public List<String> unReadPosition = new ArrayList<String>(); | |
76 | + private int voicePlayPosition = -1; | |
77 | + private LayoutInflater mLayoutInflater; | |
78 | + private boolean isGif = true; | |
79 | + public boolean isPicRefresh = true; | |
80 | + private String parentUrl = "",childPhoto; | |
81 | + | |
82 | + public interface SendErrorListener { | |
83 | + public void onClick(int position); | |
84 | + } | |
85 | + | |
86 | + public void setSendErrorListener(SendErrorListener sendErrorListener) { | |
87 | + this.sendErrorListener = sendErrorListener; | |
88 | + } | |
89 | + | |
90 | + public interface VoiceIsRead { | |
91 | + public void voiceOnClick(int position); | |
92 | + } | |
93 | + | |
94 | + public void setVoiceIsReadListener(VoiceIsRead voiceIsRead) { | |
95 | + this.voiceIsRead = voiceIsRead; | |
96 | + } | |
97 | + | |
98 | + public ChatRecyclerAdapter(Context context, List<ChatMessageBean> userList,String childPhoto) { | |
99 | + this.context = context; | |
100 | + this.userList = userList; | |
101 | + mLayoutInflater = LayoutInflater.from(context); | |
102 | + // 获取系统宽度 | |
103 | + WindowManager wManager = (WindowManager) context | |
104 | + .getSystemService(Context.WINDOW_SERVICE); | |
105 | + DisplayMetrics outMetrics = new DisplayMetrics(); | |
106 | + wManager.getDefaultDisplay().getMetrics(outMetrics); | |
107 | + mMaxItemWith = (int) (outMetrics.widthPixels * 0.5f); | |
108 | + mMinItemWith = (int) (outMetrics.widthPixels * 0.15f); | |
109 | + handler = new Handler(); | |
110 | + parentUrl= AppConfig.getAppConfig(AppContext.getInstance()).get(AppConfig.USER_IMAGE); | |
111 | + this.childPhoto=childPhoto; | |
112 | + } | |
113 | + | |
114 | + public void setIsGif(boolean isGif) { | |
115 | + this.isGif = isGif; | |
116 | + } | |
117 | + | |
118 | + public void setImageList(ArrayList<String> imageList) { | |
119 | + this.imageList = imageList; | |
120 | + } | |
121 | + | |
122 | + public void setImagePosition(HashMap<Integer, Integer> imagePosition) { | |
123 | + this.imagePosition = imagePosition; | |
124 | + } | |
125 | + | |
126 | + /** | |
127 | + * @param parent | |
128 | + * @param viewType | |
129 | + * @return | |
130 | + */ | |
131 | + @Override | |
132 | + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { | |
133 | + View view = null; | |
134 | + RecyclerView.ViewHolder holder = null; | |
135 | + switch (viewType) { | |
136 | + case FROM_USER_MSG: | |
137 | + view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_msgfrom_list_item, parent, false); | |
138 | + holder = new FromUserMsgViewHolder(view); | |
139 | + break; | |
140 | + case FROM_USER_IMG: | |
141 | + view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_imagefrom_list_item, parent, false); | |
142 | + holder = new FromUserImageViewHolder(view); | |
143 | + break; | |
144 | + case FROM_USER_VOICE: | |
145 | + view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_voicefrom_list_item, parent, false); | |
146 | + holder = new FromUserVoiceViewHolder(view); | |
147 | + break; | |
148 | + case TO_USER_MSG: | |
149 | + view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_msgto_list_item, parent, false); | |
150 | + holder = new ToUserMsgViewHolder(view); | |
151 | + break; | |
152 | + case TO_USER_IMG: | |
153 | + view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_imageto_list_item, parent, false); | |
154 | + holder = new ToUserImgViewHolder(view); | |
155 | + break; | |
156 | + case TO_USER_VOICE: | |
157 | + view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_voiceto_list_item, parent, false); | |
158 | + holder = new ToUserVoiceViewHolder(view); | |
159 | + break; | |
160 | + } | |
161 | + return holder; | |
162 | + } | |
163 | + | |
164 | + class FromUserMsgViewHolder extends RecyclerView.ViewHolder { | |
165 | + private ImageView headicon; | |
166 | + private TextView chat_time; | |
167 | + private GifTextView content; | |
168 | + | |
169 | + public FromUserMsgViewHolder(View view) { | |
170 | + super(view); | |
171 | + headicon = (ImageView) view | |
172 | + .findViewById(R.id.tb_other_user_icon); | |
173 | + chat_time = (TextView) view.findViewById(R.id.chat_time); | |
174 | + content = (GifTextView) view.findViewById(R.id.content); | |
175 | + } | |
176 | + } | |
177 | + | |
178 | + class FromUserImageViewHolder extends RecyclerView.ViewHolder { | |
179 | + private ImageView headicon; | |
180 | + private TextView chat_time; | |
181 | + private BubbleImageView image_Msg; | |
182 | + | |
183 | + public FromUserImageViewHolder(View view) { | |
184 | + super(view); | |
185 | + headicon = (ImageView) view | |
186 | + .findViewById(R.id.tb_other_user_icon); | |
187 | + chat_time = (TextView) view.findViewById(R.id.chat_time); | |
188 | + image_Msg = (BubbleImageView) view | |
189 | + .findViewById(R.id.image_message); | |
190 | + } | |
191 | + } | |
192 | + | |
193 | + class FromUserVoiceViewHolder extends RecyclerView.ViewHolder { | |
194 | + private ImageView headicon; | |
195 | + private TextView chat_time; | |
196 | + private LinearLayout voice_group; | |
197 | + private TextView voice_time; | |
198 | + private FrameLayout voice_image; | |
199 | + private View receiver_voice_unread; | |
200 | + private View voice_anim; | |
201 | + | |
202 | + public FromUserVoiceViewHolder(View view) { | |
203 | + super(view); | |
204 | + headicon = (ImageView) view | |
205 | + .findViewById(R.id.tb_other_user_icon); | |
206 | + chat_time = (TextView) view.findViewById(R.id.chat_time); | |
207 | + voice_group = (LinearLayout) view | |
208 | + .findViewById(R.id.voice_group); | |
209 | + voice_time = (TextView) view | |
210 | + .findViewById(R.id.voice_time); | |
211 | + receiver_voice_unread = (View) view | |
212 | + .findViewById(R.id.receiver_voice_unread); | |
213 | + voice_image = (FrameLayout) view | |
214 | + .findViewById(R.id.voice_receiver_image); | |
215 | + voice_anim = (View) view | |
216 | + .findViewById(R.id.id_receiver_recorder_anim); | |
217 | + } | |
218 | + } | |
219 | + | |
220 | + class ToUserMsgViewHolder extends RecyclerView.ViewHolder { | |
221 | + private ImageView headicon; | |
222 | + private TextView chat_time; | |
223 | + private GifTextView content; | |
224 | + private ImageView sendFailImg; | |
225 | + | |
226 | + public ToUserMsgViewHolder(View view) { | |
227 | + super(view); | |
228 | + headicon = (ImageView) view | |
229 | + .findViewById(R.id.tb_my_user_icon); | |
230 | + chat_time = (TextView) view | |
231 | + .findViewById(R.id.mychat_time); | |
232 | + content = (GifTextView) view | |
233 | + .findViewById(R.id.mycontent); | |
234 | + sendFailImg = (ImageView) view | |
235 | + .findViewById(R.id.mysend_fail_img); | |
236 | + } | |
237 | + } | |
238 | + | |
239 | + class ToUserImgViewHolder extends RecyclerView.ViewHolder { | |
240 | + private ImageView headicon; | |
241 | + private TextView chat_time; | |
242 | + private LinearLayout image_group; | |
243 | + private BubbleImageView image_Msg; | |
244 | + private ImageView sendFailImg; | |
245 | + | |
246 | + public ToUserImgViewHolder(View view) { | |
247 | + super(view); | |
248 | + headicon = (ImageView) view | |
249 | + .findViewById(R.id.tb_my_user_icon); | |
250 | + chat_time = (TextView) view | |
251 | + .findViewById(R.id.mychat_time); | |
252 | + sendFailImg = (ImageView) view | |
253 | + .findViewById(R.id.mysend_fail_img); | |
254 | + image_group = (LinearLayout) view | |
255 | + .findViewById(R.id.image_group); | |
256 | + image_Msg = (BubbleImageView) view | |
257 | + .findViewById(R.id.image_message); | |
258 | + } | |
259 | + } | |
260 | + | |
261 | + class ToUserVoiceViewHolder extends RecyclerView.ViewHolder { | |
262 | + private ImageView headicon; | |
263 | + private TextView chat_time; | |
264 | + private LinearLayout voice_group; | |
265 | + private TextView voice_time; | |
266 | + private FrameLayout voice_image; | |
267 | + private View receiver_voice_unread; | |
268 | + private View voice_anim; | |
269 | + private ImageView sendFailImg; | |
270 | + | |
271 | + public ToUserVoiceViewHolder(View view) { | |
272 | + super(view); | |
273 | + headicon = (ImageView) view | |
274 | + .findViewById(R.id.tb_my_user_icon); | |
275 | + chat_time = (TextView) view | |
276 | + .findViewById(R.id.mychat_time); | |
277 | + voice_group = (LinearLayout) view | |
278 | + .findViewById(R.id.voice_group); | |
279 | + voice_time = (TextView) view | |
280 | + .findViewById(R.id.voice_time); | |
281 | + voice_image = (FrameLayout) view | |
282 | + .findViewById(R.id.voice_image); | |
283 | + voice_anim = (View) view | |
284 | + .findViewById(R.id.id_recorder_anim); | |
285 | + sendFailImg = (ImageView) view | |
286 | + .findViewById(R.id.mysend_fail_img); | |
287 | + } | |
288 | + } | |
289 | + | |
290 | + /** | |
291 | + * @param holder | |
292 | + * @param position | |
293 | + */ | |
294 | + @Override | |
295 | + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { | |
296 | + ChatMessageBean tbub = userList.get(position); | |
297 | + int itemViewType = getItemViewType(position); | |
298 | + switch (itemViewType) { | |
299 | + case FROM_USER_MSG: | |
300 | + fromMsgUserLayout((FromUserMsgViewHolder) holder, tbub, position); | |
301 | + break; | |
302 | + case FROM_USER_IMG: | |
303 | + fromImgUserLayout((FromUserImageViewHolder) holder, tbub, position); | |
304 | + break; | |
305 | + case FROM_USER_VOICE: | |
306 | + fromVoiceUserLayout((FromUserVoiceViewHolder) holder, tbub, position); | |
307 | + break; | |
308 | + case TO_USER_MSG: | |
309 | + toMsgUserLayout((ToUserMsgViewHolder) holder, tbub, position); | |
310 | + break; | |
311 | + case TO_USER_IMG: | |
312 | + toImgUserLayout((ToUserImgViewHolder) holder, tbub, position); | |
313 | + break; | |
314 | + case TO_USER_VOICE: | |
315 | + toVoiceUserLayout((ToUserVoiceViewHolder) holder, tbub, position); | |
316 | + break; | |
317 | + } | |
318 | + } | |
319 | + | |
320 | + @Override | |
321 | + public int getItemViewType(int position) { | |
322 | + return userList.get(position).getType(); | |
323 | + } | |
324 | + | |
325 | + @Override | |
326 | + public int getItemCount() { | |
327 | + return userList.size(); | |
328 | + } | |
329 | + | |
330 | + private void fromMsgUserLayout(final FromUserMsgViewHolder holder, final ChatMessageBean tbub, final int position) { | |
331 | +// holder.headicon.setBackgroundResource(R.mipmap.tongbao_hiv); | |
332 | + if (!TextUtils.isEmpty(childPhoto)) | |
333 | + GlideUtils.showImg(context,holder.headicon,childPhoto); | |
334 | + else holder.headicon.setImageResource(R.drawable.header_icon); | |
335 | + /* time */ | |
336 | + if (position != 0) { | |
337 | + String showTime = getTime(tbub.getTime(), userList.get(position - 1) | |
338 | + .getTime()); | |
339 | + if (showTime != null) { | |
340 | + holder.chat_time.setVisibility(View.VISIBLE); | |
341 | + holder.chat_time.setText(showTime); | |
342 | + } else { | |
343 | + holder.chat_time.setVisibility(View.GONE); | |
344 | + } | |
345 | + } else { | |
346 | + String showTime = getTime(tbub.getTime(), null); | |
347 | + holder.chat_time.setVisibility(View.VISIBLE); | |
348 | + holder.chat_time.setText(showTime); | |
349 | + } | |
350 | + holder.content.setVisibility(View.VISIBLE); | |
351 | + holder.content.setSpanText(handler, tbub.getUserContent(), isGif); | |
352 | + } | |
353 | + | |
354 | + private void fromImgUserLayout(final FromUserImageViewHolder holder, final ChatMessageBean tbub, final int position) { | |
355 | + if (!TextUtils.isEmpty(childPhoto)) | |
356 | + GlideUtils.showImg(context,holder.headicon,childPhoto); | |
357 | + else holder.headicon.setImageResource(R.drawable.header_icon); | |
358 | + /* time */ | |
359 | + if (position != 0) { | |
360 | + String showTime = getTime(tbub.getTime(), userList.get(position - 1) | |
361 | + .getTime()); | |
362 | + if (showTime != null) { | |
363 | + holder.chat_time.setVisibility(View.VISIBLE); | |
364 | + holder.chat_time.setText(showTime); | |
365 | + } else { | |
366 | + holder.chat_time.setVisibility(View.GONE); | |
367 | + } | |
368 | + } else { | |
369 | + String showTime = getTime(tbub.getTime(), null); | |
370 | + holder.chat_time.setVisibility(View.VISIBLE); | |
371 | + holder.chat_time.setText(showTime); | |
372 | + } | |
373 | +// if (isPicRefresh) { | |
374 | + final String imageSrc = tbub.getImageLocal() == null ? "" : tbub | |
375 | + .getImageLocal(); | |
376 | + final String imageUrlSrc = tbub.getImageUrl() == null ? "" : tbub | |
377 | + .getImageUrl(); | |
378 | + final String imageIconUrl = tbub.getImageIconUrl() == null ? "" | |
379 | + : tbub.getImageIconUrl(); | |
380 | + File file = new File(imageSrc); | |
381 | + final boolean hasLocal = !imageSrc.equals("") | |
382 | + && FileSaveUtil.isFileExists(file); | |
383 | + int res; | |
384 | + res = R.drawable.chatfrom_bg_focused; | |
385 | +// Glide.with(context).load(imageSrc).transform(new CustomShapeTransformation(context, res)).into(holder.image_Msg); | |
386 | + Glide.with(context).load(imageSrc).placeholder(R.mipmap.cygs_cs).transform(new CustomShapeTransformation(context, res)).into(holder.image_Msg); | |
387 | + | |
388 | + holder.image_Msg.setOnClickListener(new View.OnClickListener() { | |
389 | + | |
390 | + @Override | |
391 | + public void onClick(View view) { | |
392 | + // TODO Auto-generated method stub | |
393 | + stopPlayVoice(); | |
394 | + Intent intent = new Intent(context, ImageViewActivity.class); | |
395 | + intent.putStringArrayListExtra("images", imageList); | |
396 | + intent.putExtra("clickedIndex", imagePosition.get(position)); | |
397 | + context.startActivity(intent); | |
398 | + } | |
399 | + | |
400 | + }); | |
401 | +// } | |
402 | + | |
403 | + } | |
404 | + | |
405 | + private void fromVoiceUserLayout(final FromUserVoiceViewHolder holder, final ChatMessageBean tbub, final int position) { | |
406 | + if (!TextUtils.isEmpty(childPhoto)) | |
407 | + GlideUtils.showImg(context,holder.headicon,childPhoto); | |
408 | + else holder.headicon.setImageResource(R.drawable.header_icon); | |
409 | + /* time */ | |
410 | + if (position != 0) { | |
411 | + String showTime = getTime(tbub.getTime(), userList.get(position - 1) | |
412 | + .getTime()); | |
413 | + if (showTime != null) { | |
414 | + holder.chat_time.setVisibility(View.VISIBLE); | |
415 | + holder.chat_time.setText(showTime); | |
416 | + } else { | |
417 | + holder.chat_time.setVisibility(View.GONE); | |
418 | + } | |
419 | + } else { | |
420 | + String showTime = getTime(tbub.getTime(), null); | |
421 | + holder.chat_time.setVisibility(View.VISIBLE); | |
422 | + holder.chat_time.setText(showTime); | |
423 | + } | |
424 | + | |
425 | + holder.voice_group.setVisibility(View.VISIBLE); | |
426 | + if (holder.receiver_voice_unread != null) | |
427 | + holder.receiver_voice_unread.setVisibility(View.GONE); | |
428 | + if (holder.receiver_voice_unread != null && unReadPosition != null) { | |
429 | + for (String unRead : unReadPosition) { | |
430 | + if (unRead.equals(position + "")) { | |
431 | + holder.receiver_voice_unread | |
432 | + .setVisibility(View.VISIBLE); | |
433 | + break; | |
434 | + } | |
435 | + } | |
436 | + } | |
437 | + AnimationDrawable drawable; | |
438 | + holder.voice_anim.setId(position); | |
439 | + if (position == voicePlayPosition) { | |
440 | + holder.voice_anim | |
441 | + .setBackgroundResource(R.mipmap.receiver_voice_node_playing003); | |
442 | + holder.voice_anim | |
443 | + .setBackgroundResource(R.drawable.voice_play_receiver); | |
444 | + drawable = (AnimationDrawable) holder.voice_anim | |
445 | + .getBackground(); | |
446 | + drawable.start(); | |
447 | + } else { | |
448 | + holder.voice_anim | |
449 | + .setBackgroundResource(R.mipmap.receiver_voice_node_playing003); | |
450 | + } | |
451 | + holder.voice_group.setOnClickListener(new View.OnClickListener() { | |
452 | + | |
453 | + @Override | |
454 | + public void onClick(View v) { | |
455 | + // TODO Auto-generated method stub | |
456 | + if (holder.receiver_voice_unread != null) | |
457 | + holder.receiver_voice_unread.setVisibility(View.GONE); | |
458 | + holder.voice_anim | |
459 | + .setBackgroundResource(R.mipmap.receiver_voice_node_playing003); | |
460 | + stopPlayVoice(); | |
461 | + voicePlayPosition = holder.voice_anim.getId(); | |
462 | + AnimationDrawable drawable; | |
463 | + holder.voice_anim | |
464 | + .setBackgroundResource(R.drawable.voice_play_receiver); | |
465 | + drawable = (AnimationDrawable) holder.voice_anim | |
466 | + .getBackground(); | |
467 | + drawable.start(); | |
468 | + String voicePath = tbub.getUserVoicePath() == null ? "" : tbub | |
469 | + .getUserVoicePath(); | |
470 | + File file = new File(voicePath); | |
471 | + if (!(!voicePath.equals("") && FileSaveUtil | |
472 | + .isFileExists(file))) { | |
473 | + voicePath = tbub.getUserVoiceUrl() == null ? "" | |
474 | + : tbub.getUserVoiceUrl(); | |
475 | + } | |
476 | + if (voiceIsRead != null) { | |
477 | + voiceIsRead.voiceOnClick(position); | |
478 | + } | |
479 | + MediaManager.playSound(voicePath, | |
480 | + new MediaPlayer.OnCompletionListener() { | |
481 | + | |
482 | + @Override | |
483 | + public void onCompletion(MediaPlayer mp) { | |
484 | + voicePlayPosition = -1; | |
485 | + holder.voice_anim | |
486 | + .setBackgroundResource(R.mipmap.receiver_voice_node_playing003); | |
487 | + } | |
488 | + }); | |
489 | + } | |
490 | + | |
491 | + }); | |
492 | + float voiceTime = tbub.getUserVoiceTime(); | |
493 | + BigDecimal b = new BigDecimal(voiceTime); | |
494 | + float f1 = b.setScale(1, BigDecimal.ROUND_HALF_UP).floatValue(); | |
495 | + holder.voice_time.setText(f1 + "\""); | |
496 | + ViewGroup.LayoutParams lParams = holder.voice_image | |
497 | + .getLayoutParams(); | |
498 | + lParams.width = (int) (mMinItemWith + mMaxItemWith / 60f | |
499 | + * tbub.getUserVoiceTime()); | |
500 | + holder.voice_image.setLayoutParams(lParams); | |
501 | + } | |
502 | + | |
503 | + private void toMsgUserLayout(final ToUserMsgViewHolder holder, final ChatMessageBean tbub, final int position) { | |
504 | +// holder.headicon.setBackgroundResource(R.mipmap.grzx_tx_s); | |
505 | +// holder.headicon.setImageDrawable(context.getResources() | |
506 | +// .getDrawable(R.mipmap.grzx_tx_s)); | |
507 | + if (!TextUtils.isEmpty(parentUrl)) | |
508 | + GlideUtils.showImg(context,holder.headicon,parentUrl); | |
509 | + else holder.headicon.setImageResource(R.drawable.header_icon); | |
510 | + /* time */ | |
511 | + if (position != 0) { | |
512 | + String showTime = getTime(tbub.getTime(), userList.get(position - 1) | |
513 | + .getTime()); | |
514 | + if (showTime != null) { | |
515 | + holder.chat_time.setVisibility(View.VISIBLE); | |
516 | + holder.chat_time.setText(showTime); | |
517 | + } else { | |
518 | + holder.chat_time.setVisibility(View.GONE); | |
519 | + } | |
520 | + } else { | |
521 | + String showTime = getTime(tbub.getTime(), null); | |
522 | + holder.chat_time.setVisibility(View.VISIBLE); | |
523 | + holder.chat_time.setText(showTime); | |
524 | + } | |
525 | + | |
526 | + holder.content.setVisibility(View.VISIBLE); | |
527 | + holder.content.setSpanText(handler, tbub.getUserContent(), isGif); | |
528 | + } | |
529 | + | |
530 | + private void toImgUserLayout(final ToUserImgViewHolder holder, final ChatMessageBean tbub, final int position) { | |
531 | + if (!TextUtils.isEmpty(parentUrl)) | |
532 | + GlideUtils.showImg(context,holder.headicon,parentUrl); | |
533 | + else holder.headicon.setImageResource(R.drawable.header_icon); | |
534 | + switch (tbub.getSendState()) { | |
535 | + case ChatConst.SENDING: | |
536 | + an = AnimationUtils.loadAnimation(context, | |
537 | + R.anim.update_loading_progressbar_anim); | |
538 | + LinearInterpolator lin = new LinearInterpolator(); | |
539 | + an.setInterpolator(lin); | |
540 | + an.setRepeatCount(-1); | |
541 | + holder.sendFailImg | |
542 | + .setBackgroundResource(R.mipmap.xsearch_loading); | |
543 | + holder.sendFailImg.startAnimation(an); | |
544 | + an.startNow(); | |
545 | + holder.sendFailImg.setVisibility(View.VISIBLE); | |
546 | + break; | |
547 | + | |
548 | + case ChatConst.COMPLETED: | |
549 | + holder.sendFailImg.clearAnimation(); | |
550 | + holder.sendFailImg.setVisibility(View.GONE); | |
551 | + break; | |
552 | + | |
553 | + case ChatConst.SENDERROR: | |
554 | + holder.sendFailImg.clearAnimation(); | |
555 | + holder.sendFailImg | |
556 | + .setBackgroundResource(R.mipmap.msg_state_fail_resend_pressed); | |
557 | + holder.sendFailImg.setVisibility(View.VISIBLE); | |
558 | + holder.sendFailImg.setOnClickListener(new View.OnClickListener() { | |
559 | + | |
560 | + @Override | |
561 | + public void onClick(View view) { | |
562 | + // TODO Auto-generated method stub | |
563 | + if (sendErrorListener != null) { | |
564 | + sendErrorListener.onClick(position); | |
565 | + } | |
566 | + } | |
567 | + | |
568 | + }); | |
569 | + break; | |
570 | + default: | |
571 | + break; | |
572 | + } | |
573 | +// holder.headicon.setImageDrawable(context.getResources() | |
574 | +// .getDrawable(R.mipmap.grzx_tx_s)); | |
575 | + | |
576 | + /* time */ | |
577 | + if (position != 0) { | |
578 | + String showTime = getTime(tbub.getTime(), userList.get(position - 1) | |
579 | + .getTime()); | |
580 | + if (showTime != null) { | |
581 | + holder.chat_time.setVisibility(View.VISIBLE); | |
582 | + holder.chat_time.setText(showTime); | |
583 | + } else { | |
584 | + holder.chat_time.setVisibility(View.GONE); | |
585 | + } | |
586 | + } else { | |
587 | + String showTime = getTime(tbub.getTime(), null); | |
588 | + holder.chat_time.setVisibility(View.VISIBLE); | |
589 | + holder.chat_time.setText(showTime); | |
590 | + } | |
591 | + | |
592 | +// if (isPicRefresh) { | |
593 | + holder.image_group.setVisibility(View.VISIBLE); | |
594 | + final String imageSrc = tbub.getImageLocal() == null ? "" : tbub | |
595 | + .getImageLocal(); | |
596 | + final String imageUrlSrc = tbub.getImageUrl() == null ? "" : tbub | |
597 | + .getImageUrl(); | |
598 | + final String imageIconUrl = tbub.getImageIconUrl() == null ? "" | |
599 | + : tbub.getImageIconUrl(); | |
600 | + File file = new File(imageSrc); | |
601 | + final boolean hasLocal = !imageSrc.equals("") | |
602 | + && FileSaveUtil.isFileExists(file); | |
603 | + int res; | |
604 | + res = R.drawable.chatto_bg_focused; | |
605 | +// Glide.with(context).load(imageSrc).transform(new CustomShapeTransformation(context, res)).into(holder.image_Msg); | |
606 | + Glide.with(context).load(imageSrc).placeholder(R.mipmap.cygs_cs).transform(new CustomShapeTransformation(context, res)).into(holder.image_Msg); | |
607 | + | |
608 | + holder.image_Msg.setOnClickListener(new View.OnClickListener() { | |
609 | + | |
610 | + @Override | |
611 | + public void onClick(View view) { | |
612 | + // TODO Auto-generated method stub | |
613 | + stopPlayVoice(); | |
614 | + Intent intent = new Intent(context, ImageViewActivity.class); | |
615 | + intent.putStringArrayListExtra("images", imageList); | |
616 | + intent.putExtra("clickedIndex", imagePosition.get(position)); | |
617 | + context.startActivity(intent); | |
618 | + } | |
619 | + | |
620 | + }); | |
621 | +// } | |
622 | + } | |
623 | + | |
624 | + private void toVoiceUserLayout(final ToUserVoiceViewHolder holder, final ChatMessageBean tbub, final int position) { | |
625 | + if (!TextUtils.isEmpty(parentUrl)) | |
626 | + GlideUtils.showImg(context,holder.headicon,parentUrl); | |
627 | + else holder.headicon.setImageResource(R.drawable.header_icon); | |
628 | + switch (tbub.getSendState()) { | |
629 | + case ChatConst.SENDING: | |
630 | + an = AnimationUtils.loadAnimation(context, | |
631 | + R.anim.update_loading_progressbar_anim); | |
632 | + LinearInterpolator lin = new LinearInterpolator(); | |
633 | + an.setInterpolator(lin); | |
634 | + an.setRepeatCount(-1); | |
635 | + holder.sendFailImg | |
636 | + .setBackgroundResource(R.mipmap.xsearch_loading); | |
637 | + holder.sendFailImg.startAnimation(an); | |
638 | + an.startNow(); | |
639 | + holder.sendFailImg.setVisibility(View.VISIBLE); | |
640 | + break; | |
641 | + | |
642 | + case ChatConst.COMPLETED: | |
643 | + holder.sendFailImg.clearAnimation(); | |
644 | + holder.sendFailImg.setVisibility(View.GONE); | |
645 | + break; | |
646 | + | |
647 | + case ChatConst.SENDERROR: | |
648 | + holder.sendFailImg.clearAnimation(); | |
649 | + holder.sendFailImg | |
650 | + .setBackgroundResource(R.mipmap.msg_state_fail_resend_pressed); | |
651 | + holder.sendFailImg.setVisibility(View.VISIBLE); | |
652 | + holder.sendFailImg.setOnClickListener(new View.OnClickListener() { | |
653 | + | |
654 | + @Override | |
655 | + public void onClick(View view) { | |
656 | + // TODO Auto-generated method stub | |
657 | + if (sendErrorListener != null) { | |
658 | + sendErrorListener.onClick(position); | |
659 | + } | |
660 | + } | |
661 | + | |
662 | + }); | |
663 | + break; | |
664 | + default: | |
665 | + break; | |
666 | + } | |
667 | +// holder.headicon.setImageDrawable(context.getResources() | |
668 | +// .getDrawable(R.mipmap.grzx_tx_s)); | |
669 | + | |
670 | + /* time */ | |
671 | + if (position != 0) { | |
672 | + String showTime = getTime(tbub.getTime(), userList.get(position - 1) | |
673 | + .getTime()); | |
674 | + if (showTime != null) { | |
675 | + holder.chat_time.setVisibility(View.VISIBLE); | |
676 | + holder.chat_time.setText(showTime); | |
677 | + } else { | |
678 | + holder.chat_time.setVisibility(View.GONE); | |
679 | + } | |
680 | + } else { | |
681 | + String showTime = getTime(tbub.getTime(), null); | |
682 | + holder.chat_time.setVisibility(View.VISIBLE); | |
683 | + holder.chat_time.setText(showTime); | |
684 | + } | |
685 | + holder.voice_group.setVisibility(View.VISIBLE); | |
686 | + if (holder.receiver_voice_unread != null) | |
687 | + holder.receiver_voice_unread.setVisibility(View.GONE); | |
688 | + if (holder.receiver_voice_unread != null && unReadPosition != null) { | |
689 | + for (String unRead : unReadPosition) { | |
690 | + if (unRead.equals(position + "")) { | |
691 | + holder.receiver_voice_unread | |
692 | + .setVisibility(View.VISIBLE); | |
693 | + break; | |
694 | + } | |
695 | + } | |
696 | + } | |
697 | + AnimationDrawable drawable; | |
698 | + holder.voice_anim.setId(position); | |
699 | + if (position == voicePlayPosition) { | |
700 | + holder.voice_anim.setBackgroundResource(R.mipmap.adj); | |
701 | + holder.voice_anim | |
702 | + .setBackgroundResource(R.drawable.voice_play_send); | |
703 | + drawable = (AnimationDrawable) holder.voice_anim | |
704 | + .getBackground(); | |
705 | + drawable.start(); | |
706 | + } else { | |
707 | + holder.voice_anim.setBackgroundResource(R.mipmap.adj); | |
708 | + } | |
709 | + holder.voice_group.setOnClickListener(new View.OnClickListener() { | |
710 | + | |
711 | + @Override | |
712 | + public void onClick(View v) { | |
713 | + // TODO Auto-generated method stub | |
714 | + if (holder.receiver_voice_unread != null) | |
715 | + holder.receiver_voice_unread.setVisibility(View.GONE); | |
716 | + holder.voice_anim.setBackgroundResource(R.mipmap.adj); | |
717 | + stopPlayVoice(); | |
718 | + voicePlayPosition = holder.voice_anim.getId(); | |
719 | + AnimationDrawable drawable; | |
720 | + holder.voice_anim | |
721 | + .setBackgroundResource(R.drawable.voice_play_send); | |
722 | + drawable = (AnimationDrawable) holder.voice_anim | |
723 | + .getBackground(); | |
724 | + drawable.start(); | |
725 | + String voicePath = tbub.getUserVoiceUrl() == null ? "" | |
726 | + : tbub.getUserVoiceUrl(); | |
727 | + if (voiceIsRead != null) { | |
728 | + voiceIsRead.voiceOnClick(position); | |
729 | + } | |
730 | + MediaManager.playSound(voicePath, | |
731 | + new MediaPlayer.OnCompletionListener() { | |
732 | + | |
733 | + @Override | |
734 | + public void onCompletion(MediaPlayer mp) { | |
735 | + voicePlayPosition = -1; | |
736 | + holder.voice_anim | |
737 | + .setBackgroundResource(R.mipmap.adj); | |
738 | + } | |
739 | + }); | |
740 | + } | |
741 | + | |
742 | + }); | |
743 | + float voiceTime = tbub.getUserVoiceTime(); | |
744 | + BigDecimal b = new BigDecimal(voiceTime); | |
745 | + float f1 = b.setScale(1, BigDecimal.ROUND_HALF_UP).floatValue(); | |
746 | + holder.voice_time.setText(f1 + "\""); | |
747 | + ViewGroup.LayoutParams lParams = holder.voice_image | |
748 | + .getLayoutParams(); | |
749 | + lParams.width = (int) (mMinItemWith + mMaxItemWith / 60f | |
750 | + * tbub.getUserVoiceTime()); | |
751 | + holder.voice_image.setLayoutParams(lParams); | |
752 | + } | |
753 | + | |
754 | + @SuppressLint("SimpleDateFormat") | |
755 | + public String getTime(String time, String before) { | |
756 | + String show_time = null; | |
757 | + if (before != null) { | |
758 | + try { | |
759 | + DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); | |
760 | + java.util.Date now = df.parse(time); | |
761 | + java.util.Date date = df.parse(before); | |
762 | + long l = now.getTime() - date.getTime(); | |
763 | + long day = l / (24 * 60 * 60 * 1000); | |
764 | + long hour = (l / (60 * 60 * 1000) - day * 24); | |
765 | + long min = ((l / (60 * 1000)) - day * 24 * 60 - hour * 60); | |
766 | + if (min >= 1) { | |
767 | + show_time = time.substring(11); | |
768 | + } | |
769 | + } catch (Exception e) { | |
770 | + e.printStackTrace(); | |
771 | + } | |
772 | + } else { | |
773 | + show_time = time.substring(11); | |
774 | + } | |
775 | + String getDay = getDay(time); | |
776 | + if (show_time != null && getDay != null) | |
777 | + show_time = getDay + " " + show_time; | |
778 | + return show_time; | |
779 | + } | |
780 | + | |
781 | + @SuppressLint("SimpleDateFormat") | |
782 | + public static String returnTime() { | |
783 | + SimpleDateFormat sDateFormat = new SimpleDateFormat( | |
784 | + "yyyy-MM-dd HH:mm:ss"); | |
785 | + String date = sDateFormat.format(new java.util.Date()); | |
786 | + return date; | |
787 | + } | |
788 | + | |
789 | + @SuppressLint("SimpleDateFormat") | |
790 | + public String getDay(String time) { | |
791 | + String showDay = null; | |
792 | + String nowTime = returnTime(); | |
793 | + try { | |
794 | + DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); | |
795 | + java.util.Date now = df.parse(nowTime); | |
796 | + java.util.Date date = df.parse(time); | |
797 | + long l = now.getTime() - date.getTime(); | |
798 | + long day = l / (24 * 60 * 60 * 1000); | |
799 | + if (day >= 365) { | |
800 | + showDay = time.substring(0, 10); | |
801 | + } else if (day >= 1 && day < 365) { | |
802 | + showDay = time.substring(5, 10); | |
803 | + } | |
804 | + } catch (Exception e) { | |
805 | + e.printStackTrace(); | |
806 | + } | |
807 | + return showDay; | |
808 | + } | |
809 | + | |
810 | + public static Bitmap getLoacalBitmap(String url) { | |
811 | + try { | |
812 | + ByteArrayOutputStream out; | |
813 | + FileInputStream fis = new FileInputStream(url); | |
814 | + BufferedInputStream bis = new BufferedInputStream(fis); | |
815 | + out = new ByteArrayOutputStream(); | |
816 | + @SuppressWarnings("unused") | |
817 | + int hasRead = 0; | |
818 | + byte[] buffer = new byte[1024 * 2]; | |
819 | + while ((hasRead = bis.read(buffer)) > 0) { | |
820 | + // 读出多少数据,向输出流中写入多少 | |
821 | + out.write(buffer); | |
822 | + out.flush(); | |
823 | + } | |
824 | + out.close(); | |
825 | + fis.close(); | |
826 | + bis.close(); | |
827 | + byte[] data = out.toByteArray(); | |
828 | + // 长宽减半 | |
829 | + BitmapFactory.Options opts = new BitmapFactory.Options(); | |
830 | + opts.inSampleSize = 3; | |
831 | + return BitmapFactory.decodeByteArray(data, 0, data.length, opts); | |
832 | + } catch (FileNotFoundException e) { | |
833 | + e.printStackTrace(); | |
834 | + return null; | |
835 | + } catch (IOException e) { | |
836 | + // TODO Auto-generated catch block | |
837 | + e.printStackTrace(); | |
838 | + return null; | |
839 | + } | |
840 | + } | |
841 | + | |
842 | + public void stopPlayVoice() { | |
843 | + if (voicePlayPosition != -1) { | |
844 | + View voicePlay = (View) ((Activity) context) | |
845 | + .findViewById(voicePlayPosition); | |
846 | + if (voicePlay != null) { | |
847 | + if (getItemViewType(voicePlayPosition) == FROM_USER_VOICE) { | |
848 | + voicePlay | |
849 | + .setBackgroundResource(R.mipmap.receiver_voice_node_playing003); | |
850 | + } else { | |
851 | + voicePlay.setBackgroundResource(R.mipmap.adj); | |
852 | + } | |
853 | + } | |
854 | + MediaManager.pause(); | |
855 | + voicePlayPosition = -1; | |
856 | + } | |
857 | + } | |
858 | +} | ... | ... |
... | ... | @@ -0,0 +1,71 @@ |
1 | +package com.shunzhi.parent.ui.activity.chartroom.fragment; | |
2 | + | |
3 | +import android.graphics.Bitmap; | |
4 | +import android.graphics.BitmapFactory; | |
5 | +import android.support.v4.app.Fragment; | |
6 | +import android.view.View; | |
7 | +import android.view.View.OnClickListener; | |
8 | +import android.widget.ProgressBar; | |
9 | + | |
10 | +import com.bumptech.glide.Glide; | |
11 | +import com.bumptech.glide.request.animation.GlideAnimation; | |
12 | +import com.bumptech.glide.request.target.SimpleTarget; | |
13 | +import com.polites.android.GestureImageView; | |
14 | +import com.shunzhi.parent.R; | |
15 | + | |
16 | +public class ImageViewFragment extends Fragment { | |
17 | + private String imageUrl; | |
18 | + private ProgressBar loadBar; | |
19 | + private GestureImageView imageGiv; | |
20 | + | |
21 | + public View onCreateView(android.view.LayoutInflater inflater, | |
22 | + android.view.ViewGroup container, | |
23 | + android.os.Bundle savedInstanceState) { | |
24 | + View view = inflater.inflate(R.layout.layout_images_view_item, container, | |
25 | + false); | |
26 | + init(view); | |
27 | + loadImage(imageUrl); | |
28 | + return view; | |
29 | + } | |
30 | + | |
31 | + private void init(View mView) { | |
32 | + loadBar = (ProgressBar) mView.findViewById(R.id.imageView_loading_pb); | |
33 | + imageGiv = (GestureImageView) mView | |
34 | + .findViewById(R.id.imageView_item_giv); | |
35 | + imageGiv.setOnClickListener(new OnClickListener() { | |
36 | + | |
37 | + @Override | |
38 | + public void onClick(View v) { | |
39 | + getActivity().finish(); | |
40 | + } | |
41 | + }); | |
42 | + } | |
43 | + | |
44 | + public void loadImage(String url) { | |
45 | + if (url.startsWith("http://")) { | |
46 | + Glide.with(this).load(url).asBitmap().into(new SimpleTarget<Bitmap>() { | |
47 | + @Override | |
48 | + public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) { | |
49 | + if (resource != null) { | |
50 | + imageGiv.setImageBitmap(resource); | |
51 | + loadBar.setVisibility(View.GONE); | |
52 | + imageGiv.setVisibility(View.VISIBLE); | |
53 | + } | |
54 | + } | |
55 | + }); | |
56 | + } else { | |
57 | + imageGiv.setImageBitmap(BitmapFactory.decodeFile(url)); | |
58 | + loadBar.setVisibility(View.GONE); | |
59 | + imageGiv.setVisibility(View.VISIBLE); | |
60 | + } | |
61 | + } | |
62 | + | |
63 | + public String getImageUrl() { | |
64 | + return imageUrl; | |
65 | + } | |
66 | + | |
67 | + public void setImageUrl(String imageUrl) { | |
68 | + this.imageUrl = imageUrl; | |
69 | + } | |
70 | + | |
71 | +} | ... | ... |
... | ... | @@ -0,0 +1,42 @@ |
1 | +package com.shunzhi.parent.ui.activity.message; | |
2 | + | |
3 | +import android.content.Intent; | |
4 | +import android.support.annotation.NonNull; | |
5 | +import android.support.v7.app.AppCompatActivity; | |
6 | +import android.os.Bundle; | |
7 | + | |
8 | +import com.share.mvpsdk.base.BasePresenter; | |
9 | +import com.share.mvpsdk.base.activity.BaseMVPCompatActivity; | |
10 | +import com.shunzhi.parent.R; | |
11 | +import com.shunzhi.parent.contract.leavermessage.LeaverMessage; | |
12 | +import com.shunzhi.parent.contract.leavermessage.LeaverMessageContract; | |
13 | +import com.shunzhi.parent.presenter.leavermessage.LeaverMessagePresenter; | |
14 | +import com.shunzhi.parent.ui.activity.chartroom.RecyclerViewChatActivity; | |
15 | + | |
16 | +import java.util.List; | |
17 | + | |
18 | +public class LeaverMessagesActivity extends BaseMVPCompatActivity<LeaverMessageContract.MyLeaverMessagePresenter,LeaverMessageContract.ILeaverMessageModel> | |
19 | +implements LeaverMessageContract.ILeverMessageView{ | |
20 | + | |
21 | + @Override | |
22 | + protected void initView(Bundle savedInstanceState) { | |
23 | + Intent intent = new Intent(this, RecyclerViewChatActivity.class); | |
24 | + startActivity(intent); | |
25 | + } | |
26 | + | |
27 | + @Override | |
28 | + protected int getLayoutId() { | |
29 | + return R.layout.activity_leaver_messages; | |
30 | + } | |
31 | + | |
32 | + @NonNull | |
33 | + @Override | |
34 | + public BasePresenter initPresenter() { | |
35 | + return LeaverMessagePresenter.newInstance(); | |
36 | + } | |
37 | + | |
38 | + @Override | |
39 | + public void ShowLeaverMessageList(List<LeaverMessage> leaverMessageList) { | |
40 | + | |
41 | + } | |
42 | +} | ... | ... |
... | ... | @@ -40,6 +40,7 @@ import com.shunzhi.parent.ui.activity.BankActivity; |
40 | 40 | import com.shunzhi.parent.ui.activity.MyChildActivity; |
41 | 41 | import com.shunzhi.parent.ui.activity.apply.ApplyReplaceCardActivity; |
42 | 42 | import com.shunzhi.parent.ui.activity.apply.ApplySigninActivity; |
43 | +import com.shunzhi.parent.ui.activity.chartroom.RecyclerViewChatActivity; | |
43 | 44 | import com.shunzhi.parent.ui.activity.mywebview.WebViewActivity; |
44 | 45 | |
45 | 46 | import java.util.List; |
... | ... | @@ -82,7 +83,7 @@ public class ChengZhangFragment extends BaseMVPCompatFragment<ReportContract.Rep |
82 | 83 | |
83 | 84 | private String type = "", jsonStr = ""; |
84 | 85 | |
85 | - LinearLayout layout_chengzhang, layout_report, layout_kaoqin, layout_buka, layout_qingjia; | |
86 | + LinearLayout layout_chengzhang, layout_report, layout_kaoqin, layout_buka, layout_qingjia,layout_liuyan; | |
86 | 87 | |
87 | 88 | RelativeLayout rl_noData; |
88 | 89 | |
... | ... | @@ -101,6 +102,7 @@ public class ChengZhangFragment extends BaseMVPCompatFragment<ReportContract.Rep |
101 | 102 | layout_kaoqin = view.findViewById(R.id.layout_kaoqin); |
102 | 103 | layout_buka = view.findViewById(R.id.layout_buka); |
103 | 104 | layout_qingjia = view.findViewById(R.id.layout_qingjia); |
105 | + layout_liuyan=view.findViewById(R.id.layout_liuyan); | |
104 | 106 | tvNoData = view.findViewById(R.id.tvNoData); |
105 | 107 | calendarView_month_mode = view.findViewById(R.id.calendarView_month_mode); |
106 | 108 | monthWeekMaterialCalendarView = view.findViewById(R.id.slidelayout); |
... | ... | @@ -108,6 +110,7 @@ public class ChengZhangFragment extends BaseMVPCompatFragment<ReportContract.Rep |
108 | 110 | layout_kaoqin.setOnClickListener(this); |
109 | 111 | layout_buka.setOnClickListener(this); |
110 | 112 | layout_qingjia.setOnClickListener(this); |
113 | + layout_liuyan.setOnClickListener(this); | |
111 | 114 | type = getArguments().getString("type"); |
112 | 115 | jsonStr = getArguments().getString("jsonStr"); |
113 | 116 | show(); |
... | ... | @@ -200,6 +203,13 @@ public class ChengZhangFragment extends BaseMVPCompatFragment<ReportContract.Rep |
200 | 203 | case R.id.layout_qingjia: |
201 | 204 | ToastUtils.showToast("正在努力开发中,敬请期待"); |
202 | 205 | break; |
206 | + case R.id.layout_liuyan://留言 | |
207 | + Bundle bundle = new Bundle(); | |
208 | + bundle.putString("childName",childBean.getStudentName()); | |
209 | + bundle.putString("childPhoto",childBean.getPhoto()); | |
210 | + startNewActivity(RecyclerViewChatActivity.class,bundle); | |
211 | +// startActivity(new Intent(getActivity(),RecyclerViewChatActivity.class)); | |
212 | + break; | |
203 | 213 | } |
204 | 214 | } |
205 | 215 | ... | ... |
... | ... | @@ -0,0 +1,9 @@ |
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<rotate xmlns:android="http://schemas.android.com/apk/res/android" | |
3 | + android:drawable="@mipmap/xsearch_loading" | |
4 | + android:fromDegrees="0" | |
5 | + android:toDegrees="359" | |
6 | + android:pivotX="50%" | |
7 | + android:pivotY="50%" | |
8 | + android:duration="700" | |
9 | + /> | |
0 | 10 | \ No newline at end of file | ... | ... |
903 Bytes
1 KB
135 Bytes
... | ... | @@ -0,0 +1,17 @@ |
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<shape xmlns:android="http://schemas.android.com/apk/res/android"> | |
3 | + <solid android:color="@android:color/white" /> | |
4 | + | |
5 | + <stroke | |
6 | + android:width="1dp" | |
7 | + android:color="@color/light_gray_2" /> | |
8 | + | |
9 | + <padding | |
10 | + android:bottom="1dp" | |
11 | + android:left="1dp" | |
12 | + android:right="1dp" | |
13 | + android:top="1dp" /> | |
14 | + <!-- | |
15 | + <corners android:topLeftRadius="5dp" android:topRightRadius="5dp" | |
16 | + android:bottomRightRadius="5dp" android:bottomLeftRadius="5dp"/> --> | |
17 | +</shape> | |
0 | 18 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,32 @@ |
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<selector xmlns:android="http://schemas.android.com/apk/res/android"> | |
3 | + | |
4 | + <item android:state_pressed="true"><shape android:shape="rectangle"> | |
5 | + <solid android:color="@color/light_blue2" /> | |
6 | + | |
7 | + <stroke android:width="1dp" android:color="@color/light_blue2" /> | |
8 | + | |
9 | + <padding android:bottom="1dp" android:left="1dp" android:right="1dp" android:top="1dp" /> | |
10 | + | |
11 | + <corners android:radius="2dp" /> | |
12 | + </shape></item> | |
13 | + <item android:state_focused="true"><shape android:shape="rectangle"> | |
14 | + <solid android:color="@color/light_blue2" /> | |
15 | + | |
16 | + <stroke android:width="1dp" android:color="@color/light_blue2" /> | |
17 | + | |
18 | + <padding android:bottom="1dp" android:left="1dp" android:right="1dp" android:top="1dp" /> | |
19 | + | |
20 | + <corners android:radius="2dp" /> | |
21 | + </shape></item> | |
22 | + <item><shape android:shape="rectangle"> | |
23 | + <solid android:color="@color/light_blue1" /> | |
24 | + | |
25 | + <stroke android:width="1dp" android:color="@color/light_blue1" /> | |
26 | + | |
27 | + <padding android:bottom="1dp" android:left="1dp" android:right="1dp" android:top="1dp" /> | |
28 | + | |
29 | + <corners android:radius="2dp" /> | |
30 | + </shape></item> | |
31 | + | |
32 | +</selector> | |
0 | 33 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,24 @@ |
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<animation-list xmlns:android="http://schemas.android.com/apk/res/android" > | |
3 | + | |
4 | + <item | |
5 | + android:drawable="@mipmap/receiver_voice_node_playing000" | |
6 | + android:duration="300"> | |
7 | + </item> | |
8 | + | |
9 | + <item | |
10 | + android:drawable="@mipmap/receiver_voice_node_playing001" | |
11 | + android:duration="300"> | |
12 | + </item> | |
13 | + | |
14 | + <item | |
15 | + android:drawable="@mipmap/receiver_voice_node_playing002" | |
16 | + android:duration="300"> | |
17 | + </item> | |
18 | + | |
19 | + <item | |
20 | + android:drawable="@mipmap/receiver_voice_node_playing003" | |
21 | + android:duration="300"> | |
22 | + </item> | |
23 | + | |
24 | +</animation-list> | |
0 | 25 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,19 @@ |
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<animation-list xmlns:android="http://schemas.android.com/apk/res/android" > | |
3 | + | |
4 | + <item | |
5 | + android:drawable="@mipmap/v_anim1" | |
6 | + android:duration="300"> | |
7 | + </item> | |
8 | + | |
9 | + <item | |
10 | + android:drawable="@mipmap/v_anim2" | |
11 | + android:duration="300"> | |
12 | + </item> | |
13 | + | |
14 | + <item | |
15 | + android:drawable="@mipmap/v_anim3" | |
16 | + android:duration="300"> | |
17 | + </item> | |
18 | + | |
19 | +</animation-list> | |
0 | 20 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,37 @@ |
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
3 | + android:layout_width="match_parent" | |
4 | + android:layout_height="match_parent" | |
5 | + android:orientation="vertical" > | |
6 | + <android.support.v4.view.ViewPager | |
7 | + android:id="@+id/images_vp" | |
8 | + android:layout_width="wrap_content" | |
9 | + android:layout_height="wrap_content"> | |
10 | + | |
11 | + </android.support.v4.view.ViewPager> | |
12 | + <LinearLayout | |
13 | + android:id="@+id/imageView_title_ll" | |
14 | + android:layout_width="match_parent" | |
15 | + android:layout_height="wrap_content" | |
16 | + android:layout_alignParentTop="true" | |
17 | + android:orientation="horizontal" | |
18 | + android:background="@color/zz_half_transparent" | |
19 | + android:paddingTop="5dp" | |
20 | + android:paddingBottom="5dp" | |
21 | + android:gravity="center"> | |
22 | + <TextView | |
23 | + android:id="@+id/imageView_current_tv" | |
24 | + android:layout_width="wrap_content" | |
25 | + android:layout_height="wrap_content" | |
26 | + android:text="1" | |
27 | + android:textSize="18sp" | |
28 | + android:textColor="@color/white"/> | |
29 | + <TextView | |
30 | + android:id="@+id/imageView_total_tv" | |
31 | + android:layout_width="wrap_content" | |
32 | + android:layout_height="wrap_content" | |
33 | + android:text="/8" | |
34 | + android:textSize="18sp" | |
35 | + android:textColor="@color/white"/> | |
36 | + </LinearLayout> | |
37 | +</RelativeLayout> | ... | ... |
... | ... | @@ -0,0 +1,9 @@ |
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
3 | + xmlns:app="http://schemas.android.com/apk/res-auto" | |
4 | + xmlns:tools="http://schemas.android.com/tools" | |
5 | + android:layout_width="match_parent" | |
6 | + android:layout_height="match_parent" | |
7 | + tools:context=".ui.activity.message.LeaverMessagesActivity"> | |
8 | + | |
9 | +</android.support.constraint.ConstraintLayout> | |
0 | 10 | \ No newline at end of file | ... | ... |
... | ... | @@ -105,4 +105,43 @@ |
105 | 105 | |
106 | 106 | </LinearLayout> |
107 | 107 | |
108 | + | |
109 | + <TextView | |
110 | + android:layout_width="wrap_content" | |
111 | + android:layout_height="wrap_content" | |
112 | + android:layout_gravity="center_horizontal" | |
113 | + android:layout_marginTop="@dimen/size_dp_10" | |
114 | + android:text="云视窗" | |
115 | + android:textColor="@color/textColor" | |
116 | + android:textSize="@dimen/size_dp_16" /> | |
117 | + | |
118 | + <LinearLayout | |
119 | + android:id="@+id/layout_liuyan" | |
120 | + android:layout_width="match_parent" | |
121 | + android:layout_height="?android:actionBarSize" | |
122 | + android:layout_marginLeft="@dimen/size_dp_10" | |
123 | + android:layout_marginRight="@dimen/size_dp_10" | |
124 | + android:layout_marginTop="@dimen/size_dp_10" | |
125 | + android:background="@drawable/shape_corner_bg" | |
126 | + android:orientation="horizontal"> | |
127 | + | |
128 | + <ImageView | |
129 | + android:layout_width="wrap_content" | |
130 | + android:layout_height="wrap_content" | |
131 | + android:layout_gravity="center_vertical" | |
132 | + android:layout_margin="@dimen/size_dp_5" | |
133 | + android:scaleType="fitXY" | |
134 | + android:src="@drawable/kaoqin" /> | |
135 | + | |
136 | + <TextView | |
137 | + android:layout_width="wrap_content" | |
138 | + android:layout_height="wrap_content" | |
139 | + android:layout_gravity="center_vertical" | |
140 | + android:layout_marginLeft="@dimen/size_dp_15" | |
141 | + android:text="留言板" | |
142 | + android:textColor="@color/textColor" | |
143 | + android:textSize="@dimen/size_dp_16" /> | |
144 | + | |
145 | + </LinearLayout> | |
146 | + | |
108 | 147 | </LinearLayout> |
109 | 148 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,39 @@ |
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
3 | + android:layout_width="wrap_content" | |
4 | + android:layout_height="wrap_content" | |
5 | + android:padding="5dp"> | |
6 | + | |
7 | + <TextView | |
8 | + android:id="@+id/chat_time" | |
9 | + android:layout_width="wrap_content" | |
10 | + android:layout_height="wrap_content" | |
11 | + android:layout_alignParentTop="true" | |
12 | + android:layout_centerHorizontal="true" | |
13 | + android:textColor="@color/light_gray_6" | |
14 | + android:textSize="10sp" | |
15 | + android:visibility="gone" /> | |
16 | + | |
17 | + <ImageView | |
18 | + android:id="@+id/tb_other_user_icon" | |
19 | + android:layout_width="50dp" | |
20 | + android:layout_height="50dp" | |
21 | + android:layout_alignParentLeft="true" | |
22 | + android:layout_below="@id/chat_time" /> | |
23 | + | |
24 | + <LinearLayout | |
25 | + android:layout_width="wrap_content" | |
26 | + android:layout_height="wrap_content" | |
27 | + android:layout_below="@id/chat_time" | |
28 | + android:layout_margin="5dp" | |
29 | + android:layout_toRightOf="@+id/tb_other_user_icon" | |
30 | + android:orientation="horizontal"> | |
31 | + | |
32 | + <com.shunzhi.mychartlibrary.widget.BubbleImageView | |
33 | + android:id="@+id/image_message" | |
34 | + android:layout_width="wrap_content" | |
35 | + android:layout_height="wrap_content" | |
36 | + android:scaleType="centerCrop" /> | |
37 | + </LinearLayout> | |
38 | + | |
39 | +</RelativeLayout> | |
0 | 40 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,25 @@ |
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<RelativeLayout | |
3 | + xmlns:android="http://schemas.android.com/apk/res/android" | |
4 | + xmlns:gesture-image="http://schemas.polites.com/android" | |
5 | + android:id="@+id/image_view_rl" | |
6 | + android:layout_width="fill_parent" | |
7 | + android:layout_height="fill_parent" | |
8 | + android:orientation="vertical" | |
9 | + android:background="@color/zz_half_transparent"> | |
10 | + | |
11 | + <ProgressBar | |
12 | + android:id="@+id/imageView_loading_pb" | |
13 | + android:layout_width="wrap_content" | |
14 | + android:layout_height="wrap_content" | |
15 | + android:layout_centerInParent="true" | |
16 | + /> | |
17 | + | |
18 | + <com.polites.android.GestureImageView | |
19 | + android:id="@+id/imageView_item_giv" | |
20 | + android:layout_width="fill_parent" | |
21 | + android:layout_height="fill_parent" | |
22 | + gesture-image:min-scale="0.75" | |
23 | + gesture-image:max-scale="10.0" | |
24 | + android:visibility="gone"/> | |
25 | +</RelativeLayout> | ... | ... |
... | ... | @@ -0,0 +1,54 @@ |
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
3 | + android:layout_width="wrap_content" | |
4 | + android:layout_height="wrap_content" | |
5 | + android:padding="5dp"> | |
6 | + | |
7 | + <TextView | |
8 | + android:id="@+id/mychat_time" | |
9 | + android:layout_width="wrap_content" | |
10 | + android:layout_height="wrap_content" | |
11 | + android:layout_alignParentTop="true" | |
12 | + android:layout_centerHorizontal="true" | |
13 | + android:textColor="@color/light_gray_6" | |
14 | + android:textSize="10sp" | |
15 | + android:visibility="gone" /> | |
16 | + | |
17 | + <ImageView | |
18 | + android:id="@+id/tb_my_user_icon" | |
19 | + android:layout_width="50dp" | |
20 | + android:layout_height="50dp" | |
21 | + android:layout_alignParentRight="true" | |
22 | + android:layout_below="@id/mychat_time" /> | |
23 | + | |
24 | + <LinearLayout | |
25 | + android:layout_width="wrap_content" | |
26 | + android:layout_height="wrap_content" | |
27 | + android:layout_below="@id/mychat_time" | |
28 | + android:layout_toLeftOf="@+id/tb_my_user_icon" | |
29 | + android:orientation="horizontal"> | |
30 | + | |
31 | + <ImageView | |
32 | + android:id="@+id/mysend_fail_img" | |
33 | + android:layout_width="25dp" | |
34 | + android:layout_height="25dp" | |
35 | + android:layout_gravity="center_vertical" | |
36 | + android:background="@mipmap/msg_state_fail_resend_pressed" /> | |
37 | + | |
38 | + <LinearLayout | |
39 | + android:id="@+id/image_group" | |
40 | + android:layout_width="wrap_content" | |
41 | + android:layout_height="wrap_content" | |
42 | + android:layout_margin="5dp" | |
43 | + android:orientation="vertical" | |
44 | + android:visibility="gone"> | |
45 | + | |
46 | + <com.shunzhi.mychartlibrary.widget.BubbleImageView | |
47 | + android:id="@+id/image_message" | |
48 | + android:layout_width="wrap_content" | |
49 | + android:layout_height="wrap_content" | |
50 | + android:scaleType="centerCrop" /> | |
51 | + </LinearLayout> | |
52 | + </LinearLayout> | |
53 | + | |
54 | +</RelativeLayout> | |
0 | 55 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,40 @@ |
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
3 | + android:layout_width="wrap_content" | |
4 | + android:layout_height="wrap_content" | |
5 | + android:padding="5dp"> | |
6 | + | |
7 | + <TextView | |
8 | + android:id="@+id/chat_time" | |
9 | + android:layout_width="wrap_content" | |
10 | + android:layout_height="wrap_content" | |
11 | + android:layout_alignParentTop="true" | |
12 | + android:layout_centerHorizontal="true" | |
13 | + android:textColor="@color/light_gray_6" | |
14 | + android:textSize="10sp" | |
15 | + android:visibility="gone" /> | |
16 | + | |
17 | + <ImageView | |
18 | + android:id="@+id/tb_other_user_icon" | |
19 | + android:layout_width="50dp" | |
20 | + android:layout_height="50dp" | |
21 | + android:layout_alignParentLeft="true" | |
22 | + android:layout_below="@id/chat_time" /> | |
23 | + | |
24 | + <LinearLayout | |
25 | + android:layout_width="wrap_content" | |
26 | + android:layout_height="wrap_content" | |
27 | + android:layout_below="@id/chat_time" | |
28 | + android:layout_toRightOf="@+id/tb_other_user_icon" | |
29 | + android:orientation="horizontal"> | |
30 | + | |
31 | + <com.shunzhi.mychartlibrary.widget.GifTextView | |
32 | + android:id="@+id/content" | |
33 | + android:layout_width="wrap_content" | |
34 | + android:layout_height="wrap_content" | |
35 | + android:layout_margin="5dp" | |
36 | + android:background="@drawable/chatfrom_bg_focused" | |
37 | + android:textSize="16sp" /> | |
38 | + </LinearLayout> | |
39 | + | |
40 | +</RelativeLayout> | |
0 | 41 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,41 @@ |
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
3 | + android:layout_width="wrap_content" | |
4 | + android:layout_height="wrap_content" | |
5 | + android:padding="5dp"> | |
6 | + | |
7 | + <TextView | |
8 | + android:id="@+id/mychat_time" | |
9 | + android:layout_width="wrap_content" | |
10 | + android:layout_height="wrap_content" | |
11 | + android:layout_alignParentTop="true" | |
12 | + android:layout_centerHorizontal="true" | |
13 | + android:textColor="@color/light_gray_6" | |
14 | + android:textSize="10sp" | |
15 | + android:visibility="gone" /> | |
16 | + | |
17 | + <ImageView | |
18 | + android:id="@+id/tb_my_user_icon" | |
19 | + android:layout_width="50dp" | |
20 | + android:layout_height="50dp" | |
21 | + android:layout_alignParentRight="true" | |
22 | + android:layout_below="@id/mychat_time" /> | |
23 | + | |
24 | + <LinearLayout | |
25 | + android:layout_width="wrap_content" | |
26 | + android:layout_height="wrap_content" | |
27 | + android:layout_below="@id/mychat_time" | |
28 | + android:layout_toLeftOf="@+id/tb_my_user_icon" | |
29 | + android:orientation="horizontal"> | |
30 | + | |
31 | + <com.shunzhi.mychartlibrary.widget.GifTextView | |
32 | + android:id="@+id/mycontent" | |
33 | + android:layout_width="wrap_content" | |
34 | + android:layout_height="wrap_content" | |
35 | + android:layout_margin="5dp" | |
36 | + android:background="@drawable/chatto_bg_focused" | |
37 | + android:textColor="@color/white" | |
38 | + android:textSize="16sp" /> | |
39 | + </LinearLayout> | |
40 | + | |
41 | +</RelativeLayout> | |
0 | 42 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,19 @@ |
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
3 | + android:layout_width="match_parent" | |
4 | + android:layout_height="match_parent" | |
5 | + android:orientation="vertical" > | |
6 | + <TextView | |
7 | + android:id="@+id/pull_text" | |
8 | + android:layout_width="match_parent" | |
9 | + android:layout_height="wrap_content" | |
10 | + android:text="pull to refresh!" | |
11 | + /> | |
12 | + <com.maxi.chatdemo.widget.pulltorefresh.PullToRefreshRecyclerView | |
13 | + android:id="@+id/pull_list" | |
14 | + android:layout_width="match_parent" | |
15 | + android:layout_height="match_parent" | |
16 | + android:background="#ffffff" | |
17 | + /> | |
18 | + | |
19 | +</LinearLayout> | |
0 | 20 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,71 @@ |
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
3 | + android:layout_width="wrap_content" | |
4 | + android:layout_height="wrap_content" | |
5 | + android:padding="5dp"> | |
6 | + | |
7 | + <TextView | |
8 | + android:id="@+id/chat_time" | |
9 | + android:layout_width="wrap_content" | |
10 | + android:layout_height="wrap_content" | |
11 | + android:layout_alignParentTop="true" | |
12 | + android:layout_centerHorizontal="true" | |
13 | + android:textColor="@color/light_gray_6" | |
14 | + android:textSize="10sp" | |
15 | + android:visibility="gone" /> | |
16 | + | |
17 | + <ImageView | |
18 | + android:id="@+id/tb_other_user_icon" | |
19 | + android:layout_width="50dp" | |
20 | + android:layout_height="50dp" | |
21 | + android:layout_alignParentLeft="true" | |
22 | + android:layout_below="@id/chat_time" /> | |
23 | + | |
24 | + <LinearLayout | |
25 | + android:layout_width="wrap_content" | |
26 | + android:layout_height="wrap_content" | |
27 | + android:layout_below="@id/chat_time" | |
28 | + android:layout_toRightOf="@+id/tb_other_user_icon" | |
29 | + android:orientation="horizontal"> | |
30 | + | |
31 | + <LinearLayout | |
32 | + android:id="@+id/voice_group" | |
33 | + android:layout_width="wrap_content" | |
34 | + android:layout_height="wrap_content" | |
35 | + android:layout_margin="5dp" | |
36 | + android:orientation="horizontal" | |
37 | + android:visibility="gone"> | |
38 | + | |
39 | + <FrameLayout | |
40 | + android:id="@+id/voice_receiver_image" | |
41 | + android:layout_width="wrap_content" | |
42 | + android:layout_height="wrap_content" | |
43 | + android:layout_gravity="center" | |
44 | + android:background="@drawable/chatfrom_bg_focused"> | |
45 | + | |
46 | + <View | |
47 | + android:id="@+id/id_receiver_recorder_anim" | |
48 | + android:layout_width="15dp" | |
49 | + android:layout_height="15dp" | |
50 | + android:layout_gravity="center_vertical|left" | |
51 | + android:background="@mipmap/receiver_voice_node_playing003" /> | |
52 | + | |
53 | + <View | |
54 | + android:id="@+id/receiver_voice_unread" | |
55 | + android:layout_width="10dp" | |
56 | + android:layout_height="10dp" | |
57 | + android:layout_gravity="center_vertical|right" | |
58 | + android:background="@mipmap/msg_chat_voice_unread" /> | |
59 | + </FrameLayout> | |
60 | + | |
61 | + <TextView | |
62 | + android:id="@+id/voice_time" | |
63 | + android:layout_width="wrap_content" | |
64 | + android:layout_height="wrap_content" | |
65 | + android:layout_gravity="center_vertical" | |
66 | + android:textColor="@color/middle_gray_1" /> | |
67 | + </LinearLayout> | |
68 | + | |
69 | + </LinearLayout> | |
70 | + | |
71 | +</RelativeLayout> | |
0 | 72 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,70 @@ |
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
3 | + android:layout_width="wrap_content" | |
4 | + android:layout_height="wrap_content" | |
5 | + android:padding="5dp"> | |
6 | + | |
7 | + <TextView | |
8 | + android:id="@+id/mychat_time" | |
9 | + android:layout_width="wrap_content" | |
10 | + android:layout_height="wrap_content" | |
11 | + android:layout_alignParentTop="true" | |
12 | + android:layout_centerHorizontal="true" | |
13 | + android:textColor="@color/light_gray_6" | |
14 | + android:textSize="10sp" | |
15 | + android:visibility="gone" /> | |
16 | + | |
17 | + <ImageView | |
18 | + android:id="@+id/tb_my_user_icon" | |
19 | + android:layout_width="50dp" | |
20 | + android:layout_height="50dp" | |
21 | + android:layout_alignParentRight="true" | |
22 | + android:layout_below="@id/mychat_time" /> | |
23 | + | |
24 | + <LinearLayout | |
25 | + android:layout_width="wrap_content" | |
26 | + android:layout_height="wrap_content" | |
27 | + android:layout_below="@id/mychat_time" | |
28 | + android:layout_toLeftOf="@+id/tb_my_user_icon" | |
29 | + android:orientation="horizontal"> | |
30 | + | |
31 | + <ImageView | |
32 | + android:id="@+id/mysend_fail_img" | |
33 | + android:layout_width="25dp" | |
34 | + android:layout_height="25dp" | |
35 | + android:layout_gravity="center_vertical" | |
36 | + android:background="@mipmap/msg_state_fail_resend_pressed" /> | |
37 | + | |
38 | + <LinearLayout | |
39 | + android:id="@+id/voice_group" | |
40 | + android:layout_width="wrap_content" | |
41 | + android:layout_height="wrap_content" | |
42 | + android:layout_margin="5dp" | |
43 | + android:orientation="horizontal" | |
44 | + android:visibility="gone"> | |
45 | + | |
46 | + <TextView | |
47 | + android:id="@+id/voice_time" | |
48 | + android:layout_width="wrap_content" | |
49 | + android:layout_height="wrap_content" | |
50 | + android:layout_gravity="center_vertical" | |
51 | + android:textColor="@color/middle_gray_1" /> | |
52 | + | |
53 | + <FrameLayout | |
54 | + android:id="@+id/voice_image" | |
55 | + android:layout_width="wrap_content" | |
56 | + android:layout_height="wrap_content" | |
57 | + android:layout_gravity="center" | |
58 | + android:background="@drawable/chatto_bg_focused"> | |
59 | + | |
60 | + <View | |
61 | + android:id="@+id/id_recorder_anim" | |
62 | + android:layout_width="15dp" | |
63 | + android:layout_height="15dp" | |
64 | + android:layout_gravity="center_vertical|right" | |
65 | + android:background="@mipmap/adj" /> | |
66 | + </FrameLayout> | |
67 | + </LinearLayout> | |
68 | + </LinearLayout> | |
69 | + | |
70 | +</RelativeLayout> | |
0 | 71 | \ No newline at end of file | ... | ... |
4.06 KB
3.79 KB
7.89 KB
2.24 KB
1.74 KB
1.81 KB
1.57 KB
1.42 KB
7.99 KB
7.99 KB
1.81 KB
1.59 KB
1.87 KB
3.02 KB
1.95 KB
2.25 KB
2.43 KB
3.96 KB
2.64 KB
3.34 KB
4.84 KB
1.78 KB
1.81 KB
7.24 KB
4.39 KB
2.13 KB
1.43 KB
1.21 KB
1.68 KB
1.8 KB
1.14 KB
2.54 KB
1.39 KB
1.85 KB
1.28 KB
1.98 KB
3.19 KB
3.9 KB
4.92 KB
3.37 KB
1.72 KB
3.01 KB
828 Bytes
414 Bytes
3.01 KB
2.06 KB
142 KB
1.18 KB
592 Bytes
82 Bytes
162 Bytes
356 Bytes
591 Bytes
3.32 KB
17.4 KB
18.8 KB
20.2 KB
6.92 KB
14.3 KB
14.4 KB
828 Bytes
... | ... | @@ -3,7 +3,132 @@ |
3 | 3 | <color name="colorPrimary">#3F51B5</color> |
4 | 4 | <color name="colorPrimaryDark">#303F9F</color> |
5 | 5 | <color name="colorAccent">#FF4081</color> |
6 | + <color name="three_transparent">#30ffffff</color> | |
7 | + <color name="black">#000000</color> | |
8 | + <color name="white">#ffffff</color> | |
9 | + <color name="light_gray_1">#e5e5e5</color> | |
10 | + <color name="light_gray_2">#f0f2f6</color> | |
11 | + <color name="light_gray_3">#fafafa</color> | |
12 | + <color name="light_gray_4">#f5f5f5</color> | |
13 | + <color name="light_gray_5">#f3f3f3</color> | |
14 | + <color name="light_gray_6">#aaaaaa</color> | |
15 | + <color name="light_gray_7">#f0f0f0</color> | |
16 | + <color name="light_gray_8">#666666</color> | |
17 | + <color name="light_gray_9">#f4f5f7</color> | |
18 | + <color name="light_gray_10">#bfbfbf</color> | |
19 | + <color name="light_gray_11">#f1f2f6</color> | |
20 | + <color name="light_gray_12">#333333</color> | |
21 | + <color name="middle_gray_1">#999999</color> | |
22 | + <color name="middle_gray_2">#818181</color> | |
23 | + <color name="dark_gray_1">#051b28</color> | |
24 | + <color name="dark_gray_2">#848689</color> | |
25 | + <color name="dark_gray_3">#252525</color> | |
26 | + <color name="dark_gray_4">#232326</color> | |
27 | + <color name="dark_gray_5">#f2f4f5</color> | |
6 | 28 | |
29 | + <color name="blue2">#0a85ff</color> | |
30 | + <color name="blue3">#356cb0</color> | |
31 | + <color name="blue4">#5795f3</color> | |
32 | + <color name="blue5">#2297fe</color> | |
33 | + | |
34 | + <color name="yellow">#edbb74</color> | |
35 | + <color name="yellow_1">#ffb802</color> | |
36 | + <color name="yellow_2">#fff5e5</color> | |
37 | + <color name="yellow_3">#fd9c00</color> | |
38 | + <color name="red">#ffdd2727</color> <!-- 酱红色 --> | |
39 | + <color name="red1">#c82300</color> <!-- 深红色 --> | |
40 | + <color name="red2">#e64a4b</color> | |
41 | + <color name="red3">#ff4719</color> | |
42 | + <color name="red4">#f2426c</color> | |
43 | + <color name="red5">#ff7870</color> | |
44 | + <color name="red6">#dd2727</color> | |
45 | + <color name="red7">#ff4258</color> | |
46 | + <color name="red8">#e72701</color> | |
47 | + | |
48 | + <color name="mjq_red">#ff5757</color> | |
49 | + <color name="mjq_albumback">#E1E0DE</color> | |
50 | + <color name="mjq_none_color">#00000000</color> | |
51 | + <color name="click_bg">#d9d9d9</color> | |
52 | + <color name="edit_frame_bg">#e9eaec</color> | |
53 | + <color name="light_blue1">#3097e6</color> | |
54 | + <color name="light_blue2">#503097e6</color> | |
55 | + <color name="light_blue3">#dcf4ff</color> | |
56 | + <color name="light_blue4">#84d4f9</color> | |
57 | + <color name="light_blue5">#45b1e3</color> | |
58 | + <color name="light_blue6">#3299e8</color> | |
59 | + <color name="light_blue7">#1597f2</color> | |
60 | + | |
61 | + <color name="zhu_light_blue">#346cb0</color> | |
62 | + | |
63 | + <color name="zz_light_blue">#278ff3</color> | |
64 | + <color name="zz_divider">#e6e6e6</color> | |
65 | + <color name="zz_divider1">#dedede</color> | |
66 | + <color name="zz_invest_light_gray">#808080</color> | |
67 | + <color name="zz_half_transparent">#7f000000</color> | |
68 | + <color name="black_30_transparent">#48000000</color> | |
69 | + <color name="black_50_transparent">#50000000</color> | |
70 | + <color name="zz_seven_transparent">#70ffffff</color> | |
71 | + <color name="zz_light_gray_6">#ebebeb</color> | |
72 | + <color name="zz_4_11_16">#bbbbbb</color> | |
73 | + <color name="zz_gray_22">#222222</color> | |
74 | + <color name="text_color_gray1">#626262</color> | |
75 | + <color name="lines_view">#cccccc</color> | |
76 | + <color name="navpage">#FFE1E8EB</color> | |
77 | + <color name="dark_yellow_1">#ffb84c</color> | |
78 | + <color name="dark_white_1">#feeedc</color> | |
79 | + <color name="hint_red_1">#fadcdc</color> | |
80 | + <color name="black1">#2f2f2f</color> | |
81 | + <color name="black2">#656565</color> | |
82 | + <color name="black3">#595959</color> | |
83 | + <color name="black4">#343434</color> | |
84 | + <color name="light_blue_1">#4ca4fe</color> | |
85 | + <color name="light_blue_2">#14ccca</color> | |
86 | + <color name="light_red_1">#f26464</color> | |
87 | + <color name="light_blue">#1597f2</color> | |
88 | + | |
89 | + <color name="light_gray_13">#dddddd</color> | |
90 | + <color name="light_gray_14">#838383</color> | |
91 | + <color name="light_gray_15">#999999</color> | |
92 | + <color name="light_gray_16">#f2f5f5</color> | |
93 | + <color name="light_gray_17">#f8f8f8</color> | |
94 | + <color name="light_gray_18">#c9c7c3</color> | |
95 | + <color name="light_gray_19">#b2b2b2</color> | |
96 | + <color name="light_gray_21">#a3a8ad</color> | |
97 | + <color name="light_gray_20">#d2d2d2</color> | |
98 | + <color name="light_gray_22">#b3b3b3</color> | |
99 | + <color name="light_gray_24">#a5a5a5</color> | |
100 | + <color name="light_gray_23">#929292</color> | |
101 | + <color name="light_gray_25">#e0e0e0</color> | |
102 | + <color name="red_dark">#634444</color> | |
103 | + | |
104 | + <item name="subscribe_item_text_color_normal" type="color">@color/default_text</item> | |
105 | + | |
106 | + <color name="subscribe_item_text_color_pressed">#ffb9b9b9</color> | |
107 | + <color name="default_text">#ff454545</color> | |
108 | + <color name="subscribe_item_text_color_pressed_night">#ff303030</color> | |
109 | + <color name="subscribe_item_focused_stroke">#ffd9d9d9</color> | |
110 | + <color name="subscribe_item_drag_stroke">#ffd2d2d2</color> | |
111 | + <color name="subscribe_item_drag_bg">#fff5f5f5</color> | |
112 | + <color name="subscribe_item_drag_stroke_night">#ff464646</color> | |
113 | + <color name="subscribe_item_drag_bg_night">#ff252525</color> | |
114 | + <color name="subscribe_item_selected_bg">#ffffffff</color> | |
115 | + <color name="subscribe_item_selected_stroke">#ffcc3131</color> | |
116 | + <color name="subscribe_item_disabled_bg">#ffefefef</color> | |
117 | + <color name="subscribe_item_disabled_stroke">#ffd9d9d9</color> | |
118 | + <color name="subscribe_item_pressed_bg">#fff9f9f9</color> | |
119 | + <color name="subscribe_item_pressed_stroke">#ffcdcdcd</color> | |
120 | + <color name="subscribe_item_normal_bg">#fff5f5f5</color> | |
121 | + <color name="subscribe_item_normal_stroke">#ffcdcdcd</color> | |
122 | + <color name="subscribe_item_focused_bg_night">#ff252525</color> | |
123 | + <color name="subscribe_item_focused_stroke_night">#ff464646</color> | |
124 | + <color name="subscribe_item_selected_bg_night">#ff252525</color> | |
125 | + <color name="subscribe_item_selected_stroke_night">#ffbc494d</color> | |
126 | + <color name="subscribe_item_disabled_bg_night">#ff2b2b2b</color> | |
127 | + <color name="project_detail_red">#ffcd2323</color> | |
128 | + <color name="project_detail_purple">#ff573535</color> | |
129 | + <color name="transparentWhite">#30ffffff</color> | |
130 | + <color name="transparentWhit2">#efffffff</color> | |
131 | + <color name="transparentGray">#e6e0e0e0</color> | |
7 | 132 | |
8 | 133 | <color name="hintTextColor">#494947</color> |
9 | 134 | <color name="bottomline">#B8B8B9</color> | ... | ... |
... | ... | @@ -7,4 +7,11 @@ |
7 | 7 | <string name="ceping">慧测慧练</string> |
8 | 8 | <string name="consult_huati">热门资讯</string> |
9 | 9 | <string name="order_detail">订单详情</string> |
10 | + <!-- 录音 --> | |
11 | + <string name="normal">按住 说话</string> | |
12 | + <string name="recording">松开 结束</string> | |
13 | + <string name="want_to_cancle">松开手指,取消发送</string> | |
14 | + <string name="shouzhishanghua">手指上滑,取消发送</string> | |
15 | + <string name="tooshort">录音时间过短</string> | |
16 | + <string name="toolong">录音时间过长</string> | |
10 | 17 | </resources> | ... | ... |
... | ... | @@ -82,4 +82,16 @@ |
82 | 82 | <!--<item name="colorAccent">@color/colorAccent</item>--> |
83 | 83 | </style> |
84 | 84 | |
85 | + <style name="AppBarTheme" parent="android:Theme.Holo.Light"> | |
86 | + <item name="android:windowFullscreen">false</item> | |
87 | + <item name="android:windowIsTranslucent">true</item> | |
88 | + </style> | |
89 | + | |
90 | + <style name="Theme_audioDialog" parent="@android:style/Theme.Dialog"> | |
91 | + <item name="android:windowBackground">@mipmap/tb_dialog_loading_bg</item> | |
92 | + <item name="android:windowFrame">@null</item> | |
93 | + <item name="android:windowIsFloating">true</item> | |
94 | + <item name="android:windowIsTranslucent">true</item> | |
95 | + <item name="android:backgroundDimEnabled">false</item> | |
96 | + </style> | |
85 | 97 | </resources> | ... | ... |
... | ... | @@ -38,7 +38,6 @@ android { |
38 | 38 | dependencies { |
39 | 39 | implementation fileTree(dir: 'libs', include: ['*.jar']) |
40 | 40 | |
41 | - implementation 'com.android.support:appcompat-v7:26.1.0' | |
42 | 41 | implementation 'com.android.support.constraint:constraint-layout:1.0.2' |
43 | 42 | testImplementation 'junit:junit:4.12' |
44 | 43 | androidTestImplementation 'com.android.support.test:runner:1.0.1' | ... | ... |
... | ... | @@ -0,0 +1 @@ |
1 | +/build | ... | ... |
... | ... | @@ -0,0 +1,40 @@ |
1 | +apply plugin: 'com.android.library' | |
2 | + | |
3 | +android { | |
4 | + compileSdkVersion 27 | |
5 | + | |
6 | + | |
7 | + | |
8 | + defaultConfig { | |
9 | + minSdkVersion 16 | |
10 | + targetSdkVersion 27 | |
11 | + versionCode 1 | |
12 | + versionName "1.0" | |
13 | + | |
14 | + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" | |
15 | + | |
16 | + } | |
17 | + | |
18 | + buildTypes { | |
19 | + release { | |
20 | + minifyEnabled false | |
21 | + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' | |
22 | + } | |
23 | + } | |
24 | + | |
25 | +} | |
26 | + | |
27 | +dependencies { | |
28 | + implementation fileTree(dir: 'libs', include: ['*.jar']) | |
29 | + | |
30 | + implementation 'com.android.support:appcompat-v7:27.1.1' | |
31 | + testImplementation 'junit:junit:4.12' | |
32 | + androidTestImplementation 'com.android.support.test:runner:1.0.2' | |
33 | + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' | |
34 | + implementation 'org.greenrobot:greendao:3.2.2' | |
35 | + compile "com.android.support:recyclerview-v7:27.1.1" | |
36 | + // Glide | |
37 | + compile "com.github.bumptech.glide:glide:$rootProject.glideVersion" | |
38 | + compile "com.github.bumptech.glide:okhttp-integration:$rootProject.glideokhttpVersion" | |
39 | + compile "jp.wasabeef:glide-transformations:$rootProject.glideTransformationVersion" | |
40 | +} | ... | ... |
... | ... | @@ -0,0 +1,21 @@ |
1 | +# Add project specific ProGuard rules here. | |
2 | +# You can control the set of applied configuration files using the | |
3 | +# proguardFiles setting in build.gradle. | |
4 | +# | |
5 | +# For more details, see | |
6 | +# http://developer.android.com/guide/developing/tools/proguard.html | |
7 | + | |
8 | +# If your project uses WebView with JS, uncomment the following | |
9 | +# and specify the fully qualified class name to the JavaScript interface | |
10 | +# class: | |
11 | +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { | |
12 | +# public *; | |
13 | +#} | |
14 | + | |
15 | +# Uncomment this to preserve the line number information for | |
16 | +# debugging stack traces. | |
17 | +#-keepattributes SourceFile,LineNumberTable | |
18 | + | |
19 | +# If you keep the line number information, uncomment this to | |
20 | +# hide the original source file name. | |
21 | +#-renamesourcefileattribute SourceFile | ... | ... |
... | ... | @@ -0,0 +1,26 @@ |
1 | +package com.shunzhi.mychartlibrary; | |
2 | + | |
3 | +import android.content.Context; | |
4 | +import android.support.test.InstrumentationRegistry; | |
5 | +import android.support.test.runner.AndroidJUnit4; | |
6 | + | |
7 | +import org.junit.Test; | |
8 | +import org.junit.runner.RunWith; | |
9 | + | |
10 | +import static org.junit.Assert.*; | |
11 | + | |
12 | +/** | |
13 | + * Instrumented test, which will execute on an Android device. | |
14 | + * | |
15 | + * @see <a href="http://d.android.com/tools/testing">Testing documentation</a> | |
16 | + */ | |
17 | +@RunWith(AndroidJUnit4.class) | |
18 | +public class ExampleInstrumentedTest { | |
19 | + @Test | |
20 | + public void useAppContext() { | |
21 | + // Context of the app under test. | |
22 | + Context appContext = InstrumentationRegistry.getTargetContext(); | |
23 | + | |
24 | + assertEquals("com.shunzhi.mychartlibrary.test", appContext.getPackageName()); | |
25 | + } | |
26 | +} | ... | ... |
... | ... | @@ -0,0 +1,791 @@ |
1 | +package com.shunzhi.mychartlibrary; | |
2 | + | |
3 | +import android.Manifest; | |
4 | +import android.annotation.SuppressLint; | |
5 | +import android.annotation.TargetApi; | |
6 | +import android.app.ActionBar; | |
7 | +import android.app.Activity; | |
8 | +import android.content.Intent; | |
9 | +import android.content.pm.PackageManager; | |
10 | +import android.graphics.Bitmap; | |
11 | +import android.net.Uri; | |
12 | +import android.os.Build; | |
13 | +import android.os.Bundle; | |
14 | +import android.os.Environment; | |
15 | +import android.provider.MediaStore; | |
16 | +import android.support.v4.view.ViewPager; | |
17 | +import android.text.Spannable; | |
18 | +import android.text.TextUtils; | |
19 | +import android.view.KeyEvent; | |
20 | +import android.view.View; | |
21 | +import android.widget.AdapterView; | |
22 | +import android.widget.EditText; | |
23 | +import android.widget.ImageView; | |
24 | +import android.widget.LinearLayout; | |
25 | +import android.widget.ListView; | |
26 | +import android.widget.TextView; | |
27 | +import android.widget.Toast; | |
28 | + | |
29 | + | |
30 | +import com.shunzhi.mychartlibrary.adapter.DataAdapter; | |
31 | +import com.shunzhi.mychartlibrary.adapter.ExpressionAdapter; | |
32 | +import com.shunzhi.mychartlibrary.adapter.ExpressionPagerAdapter; | |
33 | +import com.shunzhi.mychartlibrary.db.ChatDbManager; | |
34 | +import com.shunzhi.mychartlibrary.db.ChatMessageBean; | |
35 | +import com.shunzhi.mychartlibrary.utils.StatusBarUtils; | |
36 | +import com.shunzhi.mychartlibrary.common.ChatConst; | |
37 | +import com.shunzhi.mychartlibrary.utils.FileSaveUtil; | |
38 | +import com.shunzhi.mychartlibrary.utils.ImageCheckoutUtil; | |
39 | +import com.shunzhi.mychartlibrary.utils.KeyBoardUtils; | |
40 | +import com.shunzhi.mychartlibrary.utils.PictureUtil; | |
41 | +import com.shunzhi.mychartlibrary.utils.ScreenUtil; | |
42 | +import com.shunzhi.mychartlibrary.utils.SmileUtils; | |
43 | +import com.shunzhi.mychartlibrary.widget.AudioRecordButton; | |
44 | +import com.shunzhi.mychartlibrary.widget.ChatBottomView; | |
45 | +import com.shunzhi.mychartlibrary.widget.ExpandGridView; | |
46 | +import com.shunzhi.mychartlibrary.widget.HeadIconSelectorView; | |
47 | +import com.shunzhi.mychartlibrary.widget.MediaManager; | |
48 | +import com.shunzhi.mychartlibrary.widget.pulltorefresh.PullToRefreshLayout; | |
49 | + | |
50 | +import java.io.File; | |
51 | +import java.io.FileInputStream; | |
52 | +import java.io.FileNotFoundException; | |
53 | +import java.io.IOException; | |
54 | +import java.lang.reflect.Field; | |
55 | +import java.text.SimpleDateFormat; | |
56 | +import java.util.ArrayList; | |
57 | +import java.util.HashMap; | |
58 | +import java.util.List; | |
59 | +import java.util.Map; | |
60 | + | |
61 | +/** | |
62 | + * Created by Mao Jiqing on 2016/10/20. | |
63 | + */ | |
64 | +public abstract class BaseActivity extends Activity { | |
65 | + public PullToRefreshLayout pullList; | |
66 | + public boolean isDown = false; | |
67 | + private boolean CAN_WRITE_EXTERNAL_STORAGE = true; | |
68 | + private boolean CAN_RECORD_AUDIO = true; | |
69 | + public int position; //加载滚动刷新位置 | |
70 | + public int bottomStatusHeight = 0; | |
71 | + public int listSlideHeight = 0;//滑动距离 | |
72 | + public TextView send_emoji_icon; | |
73 | + public ImageView emoji; | |
74 | + public ImageView mess_iv; | |
75 | + public ImageView voiceIv; | |
76 | + public ListView mess_lv; | |
77 | + public ChatBottomView tbbv; | |
78 | + private DataAdapter adapter; | |
79 | + public AudioRecordButton voiceBtn; | |
80 | + public EditText mEditTextContent; | |
81 | + public ViewPager expressionViewpager; | |
82 | + public LinearLayout emoji_group; | |
83 | + private File mCurrentPhotoFile; | |
84 | + public View activityRootView; | |
85 | + private Toast mToast; | |
86 | + public String userName = "test";//聊天对象昵称 | |
87 | + private String permissionInfo; | |
88 | + private String camPicPath; | |
89 | + public String item[] = {"你好!", "我正忙着呢,等等", "有啥事吗?", "有时间聊聊吗", "再见!"}; | |
90 | + public List<ChatMessageBean> tblist = new ArrayList<ChatMessageBean>(); | |
91 | + private List<String> reslist; | |
92 | + public ChatDbManager mChatDbManager; | |
93 | + public int page = 0; | |
94 | + public int number = 10; | |
95 | + public List<ChatMessageBean> pagelist = new ArrayList<ChatMessageBean>(); | |
96 | + public ArrayList<String> imageList = new ArrayList<String>();//adapter图片数据 | |
97 | + public HashMap<Integer, Integer> imagePosition = new HashMap<Integer, Integer>();//图片下标位置 | |
98 | + private static final int SDK_PERMISSION_REQUEST = 127; | |
99 | + private static final int IMAGE_SIZE = 100 * 1024;// 300kb | |
100 | + public static final int SEND_OK = 0x1110; | |
101 | + public static final int REFRESH = 0x0011; | |
102 | + public static final int RECERIVE_OK = 0x1111; | |
103 | + public static final int PULL_TO_REFRESH_DOWN = 0x0111; | |
104 | + | |
105 | + /** | |
106 | + * 发送文本消息 | |
107 | + */ | |
108 | + protected abstract void sendMessage(); | |
109 | + | |
110 | + /** | |
111 | + * 发送图片文件 | |
112 | + * | |
113 | + * @param filePath | |
114 | + */ | |
115 | + protected abstract void sendImage(String filePath); | |
116 | + | |
117 | + /** | |
118 | + * 发送语音消息 | |
119 | + * | |
120 | + * @param seconds | |
121 | + * @param filePath | |
122 | + */ | |
123 | + protected abstract void sendVoice(float seconds, String filePath); | |
124 | + | |
125 | + protected abstract void loadRecords(); | |
126 | + | |
127 | + @Override | |
128 | + protected void onCreate(Bundle savedInstanceState) { | |
129 | + super.onCreate(savedInstanceState); | |
130 | + setContentView(R.layout.activity_chat); | |
131 | + StatusBarUtils.setBarColor(this,getResources().getColor(R.color.titleColor)); | |
132 | + findView(); | |
133 | + initpop(); | |
134 | + init(); | |
135 | + // after andrioid m,must request Permiision on runtime | |
136 | + getPersimmions(); | |
137 | + } | |
138 | + | |
139 | + @Override | |
140 | + protected void onDestroy() { | |
141 | + MediaManager.pause(); | |
142 | + MediaManager.release(); | |
143 | + cancelToast(); | |
144 | + super.onDestroy(); | |
145 | + } | |
146 | + | |
147 | + protected void findView() { | |
148 | + pullList = (PullToRefreshLayout) findViewById(R.id.content_lv); | |
149 | + activityRootView = findViewById(R.id.layout_tongbao_rl); | |
150 | + mEditTextContent = (EditText) findViewById(R.id.mess_et); | |
151 | + mess_iv = (ImageView) findViewById(R.id.mess_iv); | |
152 | + emoji = (ImageView) findViewById(R.id.emoji); | |
153 | + voiceIv = (ImageView) findViewById(R.id.voice_iv); | |
154 | + expressionViewpager = (ViewPager) findViewById(R.id.vPager); | |
155 | + voiceBtn = (AudioRecordButton) findViewById(R.id.voice_btn); | |
156 | + emoji_group = (LinearLayout) findViewById(R.id.emoji_group); | |
157 | + send_emoji_icon = (TextView) findViewById(R.id.send_emoji_icon); | |
158 | + tbbv = (ChatBottomView) findViewById(R.id.other_lv); | |
159 | + initActionBar(); | |
160 | + } | |
161 | + | |
162 | + protected void init() { | |
163 | + mEditTextContent.setOnKeyListener(onKeyListener); | |
164 | + mChatDbManager = new ChatDbManager(); | |
165 | + PullToRefreshLayout.pulltorefreshNotifier pullNotifier = new PullToRefreshLayout.pulltorefreshNotifier() { | |
166 | + @Override | |
167 | + public void onPull() { | |
168 | + // TODO Auto-generated method stub | |
169 | + downLoad(); | |
170 | + } | |
171 | + }; | |
172 | + pullList.setpulltorefreshNotifier(pullNotifier); | |
173 | + voiceIv.setOnClickListener(new View.OnClickListener() { | |
174 | + | |
175 | + @Override | |
176 | + public void onClick(View arg0) { | |
177 | + // TODO Auto-generated method stub | |
178 | + if (voiceBtn.getVisibility() == View.GONE) { | |
179 | + emoji.setBackgroundResource(R.mipmap.emoji); | |
180 | + mess_iv.setBackgroundResource(R.mipmap.tb_more); | |
181 | + mEditTextContent.setVisibility(View.GONE); | |
182 | + emoji_group.setVisibility(View.GONE); | |
183 | + tbbv.setVisibility(View.GONE); | |
184 | + mess_lv.setVisibility(View.GONE); | |
185 | + voiceBtn.setVisibility(View.VISIBLE); | |
186 | + KeyBoardUtils.hideKeyBoard(BaseActivity.this, | |
187 | + mEditTextContent); | |
188 | + voiceIv.setBackgroundResource(R.mipmap.chatting_setmode_keyboard_btn_normal); | |
189 | + } else { | |
190 | + mEditTextContent.setVisibility(View.VISIBLE); | |
191 | + voiceBtn.setVisibility(View.GONE); | |
192 | + voiceIv.setBackgroundResource(R.mipmap.voice_btn_normal); | |
193 | + KeyBoardUtils.showKeyBoard(BaseActivity.this, mEditTextContent); | |
194 | + } | |
195 | + } | |
196 | + | |
197 | + }); | |
198 | + mess_iv.setOnClickListener(new View.OnClickListener() { | |
199 | + | |
200 | + @SuppressLint("NewApi") | |
201 | + @Override | |
202 | + public void onClick(View v) { | |
203 | + // TODO Auto-generated method stub | |
204 | + emoji_group.setVisibility(View.GONE); | |
205 | + if (tbbv.getVisibility() == View.GONE | |
206 | + && mess_lv.getVisibility() == View.GONE) { | |
207 | + mEditTextContent.setVisibility(View.VISIBLE); | |
208 | + mess_iv.setFocusable(true); | |
209 | + voiceBtn.setVisibility(View.GONE); | |
210 | + emoji.setBackgroundResource(R.mipmap.emoji); | |
211 | + voiceIv.setBackgroundResource(R.mipmap.voice_btn_normal); | |
212 | + tbbv.setVisibility(View.VISIBLE); | |
213 | + KeyBoardUtils.hideKeyBoard(BaseActivity.this, | |
214 | + mEditTextContent); | |
215 | + mess_iv.setBackgroundResource(R.mipmap.chatting_setmode_keyboard_btn_normal); | |
216 | + } else { | |
217 | + tbbv.setVisibility(View.GONE); | |
218 | + KeyBoardUtils.showKeyBoard(BaseActivity.this, mEditTextContent); | |
219 | + mess_iv.setBackgroundResource(R.mipmap.tb_more); | |
220 | + if (mess_lv.getVisibility() != View.GONE) { | |
221 | + mess_lv.setVisibility(View.GONE); | |
222 | + KeyBoardUtils.showKeyBoard(BaseActivity.this, mEditTextContent); | |
223 | + mess_iv.setBackgroundResource(R.mipmap.tb_more); | |
224 | + } | |
225 | + } | |
226 | + } | |
227 | + }); | |
228 | + send_emoji_icon.setOnClickListener(new View.OnClickListener() { | |
229 | + | |
230 | + @Override | |
231 | + public void onClick(View arg0) { | |
232 | + // TODO Auto-generated method stub | |
233 | + sendMessage(); | |
234 | + } | |
235 | + | |
236 | + }); | |
237 | + tbbv.setOnHeadIconClickListener(new HeadIconSelectorView.OnHeadIconClickListener() { | |
238 | + | |
239 | + @SuppressLint("InlinedApi") | |
240 | + @Override | |
241 | + public void onClick(int from) { | |
242 | + switch (from) { | |
243 | + case ChatBottomView.FROM_CAMERA: | |
244 | + if (!CAN_WRITE_EXTERNAL_STORAGE) { | |
245 | + Toast.makeText(BaseActivity.this, "权限未开通\n请到设置中开通相册权限", Toast.LENGTH_SHORT).show(); | |
246 | + } else { | |
247 | + final String state = Environment.getExternalStorageState(); | |
248 | + if (Environment.MEDIA_MOUNTED.equals(state)) { | |
249 | + camPicPath = getSavePicPath(); | |
250 | + Intent openCameraIntent = new Intent( | |
251 | + MediaStore.ACTION_IMAGE_CAPTURE); | |
252 | + Uri uri = Uri.fromFile(new File(camPicPath)); | |
253 | + openCameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri); | |
254 | + startActivityForResult(openCameraIntent, | |
255 | + ChatBottomView.FROM_CAMERA); | |
256 | + } else { | |
257 | + showToast("请检查内存卡"); | |
258 | + } | |
259 | + } | |
260 | + break; | |
261 | + case ChatBottomView.FROM_GALLERY: | |
262 | + if (!CAN_WRITE_EXTERNAL_STORAGE) { | |
263 | + Toast.makeText(BaseActivity.this, "权限未开通\n请到设置中开通相册权限", Toast.LENGTH_SHORT).show(); | |
264 | + } else { | |
265 | + String status = Environment.getExternalStorageState(); | |
266 | + if (status.equals(Environment.MEDIA_MOUNTED)) {// 判断是否有SD卡 | |
267 | + Intent intent = new Intent(); | |
268 | + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { | |
269 | + intent.setAction(Intent.ACTION_GET_CONTENT); | |
270 | + } else { | |
271 | + intent.setAction(Intent.ACTION_OPEN_DOCUMENT); | |
272 | + intent.addCategory(Intent.CATEGORY_OPENABLE); | |
273 | + intent.putExtra("crop", "true"); | |
274 | + intent.putExtra("scale", "true"); | |
275 | + intent.putExtra("scaleUpIfNeeded", true); | |
276 | + } | |
277 | + intent.setType("image/*"); | |
278 | + startActivityForResult(intent, | |
279 | + ChatBottomView.FROM_GALLERY); | |
280 | + } else { | |
281 | + showToast("没有SD卡"); | |
282 | + } | |
283 | + } | |
284 | + break; | |
285 | + | |
286 | + case ChatBottomView.FROM_PHRASE: | |
287 | + if (mess_lv.getVisibility() == View.GONE) { | |
288 | + tbbv.setVisibility(View.GONE); | |
289 | + emoji.setBackgroundResource(R.mipmap.emoji); | |
290 | + voiceIv.setBackgroundResource(R.mipmap.voice_btn_normal); | |
291 | + mess_lv.setVisibility(View.VISIBLE); | |
292 | + KeyBoardUtils.hideKeyBoard(BaseActivity.this, | |
293 | + mEditTextContent); | |
294 | + mess_iv.setBackgroundResource(R.mipmap.chatting_setmode_keyboard_btn_normal); | |
295 | + } | |
296 | + } | |
297 | + } | |
298 | + | |
299 | + }); | |
300 | + emoji.setOnClickListener(new View.OnClickListener() { | |
301 | + | |
302 | + @Override | |
303 | + public void onClick(View v) { | |
304 | + // TODO Auto-generated method stub | |
305 | + mess_lv.setVisibility(View.GONE); | |
306 | + tbbv.setVisibility(View.GONE); | |
307 | + if (emoji_group.getVisibility() == View.GONE) { | |
308 | + mEditTextContent.setVisibility(View.VISIBLE); | |
309 | + voiceBtn.setVisibility(View.GONE); | |
310 | + voiceIv.setBackgroundResource(R.mipmap.voice_btn_normal); | |
311 | + mess_iv.setBackgroundResource(R.mipmap.tb_more); | |
312 | + emoji_group.setVisibility(View.VISIBLE); | |
313 | + emoji.setBackgroundResource(R.mipmap.chatting_setmode_keyboard_btn_normal); | |
314 | + KeyBoardUtils.hideKeyBoard(BaseActivity.this, | |
315 | + mEditTextContent); | |
316 | + } else { | |
317 | + emoji_group.setVisibility(View.GONE); | |
318 | + emoji.setBackgroundResource(R.mipmap.emoji); | |
319 | + KeyBoardUtils.showKeyBoard(BaseActivity.this, mEditTextContent); | |
320 | + } | |
321 | + } | |
322 | + }); | |
323 | + // 表情list | |
324 | + reslist = getExpressionRes(40); | |
325 | + // 初始化表情viewpager | |
326 | + List<View> views = new ArrayList<View>(); | |
327 | + View gv1 = getGridChildView(1); | |
328 | + View gv2 = getGridChildView(2); | |
329 | + views.add(gv1); | |
330 | + views.add(gv2); | |
331 | + expressionViewpager.setAdapter(new ExpressionPagerAdapter(views)); | |
332 | + | |
333 | + mEditTextContent.setOnClickListener(new View.OnClickListener() { | |
334 | + | |
335 | + @Override | |
336 | + public void onClick(View v) { | |
337 | + // TODO Auto-generated method stub | |
338 | + emoji_group.setVisibility(View.GONE); | |
339 | + tbbv.setVisibility(View.GONE); | |
340 | + mess_lv.setVisibility(View.GONE); | |
341 | + emoji.setBackgroundResource(R.mipmap.emoji); | |
342 | + mess_iv.setBackgroundResource(R.mipmap.tb_more); | |
343 | + voiceIv.setBackgroundResource(R.mipmap.voice_btn_normal); | |
344 | + } | |
345 | + | |
346 | + }); | |
347 | + | |
348 | + mess_lv.setOnItemClickListener(new AdapterView.OnItemClickListener() { | |
349 | + | |
350 | + @Override | |
351 | + public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, | |
352 | + long arg3) { | |
353 | + // TODO Auto-generated method stub | |
354 | + mEditTextContent.setText(item[arg2]); | |
355 | + sendMessage(); | |
356 | + } | |
357 | + | |
358 | + }); | |
359 | +// controlKeyboardLayout(activityRootView, pullList); | |
360 | + bottomStatusHeight = ScreenUtil.getNavigationBarHeight(this); | |
361 | + //加载本地聊天记录 | |
362 | + page = (int) mChatDbManager.getPages(number); | |
363 | + loadRecords(); | |
364 | + } | |
365 | + | |
366 | + private void initActionBar() { | |
367 | + if (getActionBar() == null) { | |
368 | + return; | |
369 | + } | |
370 | +// getActionBar().setBackgroundDrawable(getResources().getDrawable(R.drawable.ab_bg));//ActionBar的背景图片 | |
371 | + getActionBar().setCustomView(R.layout.layout_action_bar);//ActionBar的自定义布局文件 | |
372 | + getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM); | |
373 | + View.OnClickListener listener = new View.OnClickListener() { | |
374 | + @Override | |
375 | + public void onClick(View v) { | |
376 | + if(v.getId()==R.id.ivLeft){ | |
377 | + doLeft(); | |
378 | + }else if (v.getId()==R.id.ivRight){ | |
379 | + doRight(); | |
380 | + }else if (v.getId()==R.id.llRight){ | |
381 | + doRight(); | |
382 | + } | |
383 | + } | |
384 | + }; | |
385 | + getActionBar().getCustomView().findViewById(R.id.ivLeft).setOnClickListener(listener); | |
386 | + getActionBar().getCustomView().findViewById(R.id.ivRight).setOnClickListener(listener); | |
387 | + getActionBar().getCustomView().findViewById(R.id.llRight).setOnClickListener(listener); | |
388 | + ((TextView) getActionBar().getCustomView().findViewById(R.id.tvTitle)).setText(getTitle().toString()); | |
389 | + } | |
390 | + | |
391 | + @TargetApi(23) | |
392 | + protected void getPersimmions() { | |
393 | + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { | |
394 | + ArrayList<String> permissions = new ArrayList<String>(); | |
395 | + // 读写权限 | |
396 | + if (addPermission(permissions, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { | |
397 | + permissionInfo += "Manifest.permission.WRITE_EXTERNAL_STORAGE Deny \n"; | |
398 | + } | |
399 | + // 麦克风权限 | |
400 | + if (addPermission(permissions, Manifest.permission.RECORD_AUDIO)) { | |
401 | + permissionInfo += "Manifest.permission.WRITE_EXTERNAL_STORAGE Deny \n"; | |
402 | + } | |
403 | + if (permissions.size() > 0) { | |
404 | + requestPermissions(permissions.toArray(new String[permissions.size()]), SDK_PERMISSION_REQUEST); | |
405 | + } | |
406 | + } | |
407 | + } | |
408 | + | |
409 | + @TargetApi(23) | |
410 | + private boolean addPermission(ArrayList<String> permissionsList, String permission) { | |
411 | + if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) { // 如果应用没有获得对应权限,则添加到列表中,准备批量申请 | |
412 | + if (shouldShowRequestPermissionRationale(permission)) { | |
413 | + return true; | |
414 | + } else { | |
415 | + permissionsList.add(permission); | |
416 | + return false; | |
417 | + } | |
418 | + | |
419 | + } else { | |
420 | + return true; | |
421 | + } | |
422 | + } | |
423 | + | |
424 | + @TargetApi(23) | |
425 | + @Override | |
426 | + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { | |
427 | + // TODO Auto-generated method stub | |
428 | + super.onRequestPermissionsResult(requestCode, permissions, grantResults); | |
429 | + switch (requestCode) { | |
430 | + case SDK_PERMISSION_REQUEST: | |
431 | + Map<String, Integer> perms = new HashMap<String, Integer>(); | |
432 | + // Initial | |
433 | + perms.put(Manifest.permission.WRITE_EXTERNAL_STORAGE, PackageManager.PERMISSION_GRANTED); | |
434 | + perms.put(Manifest.permission.RECORD_AUDIO, PackageManager.PERMISSION_GRANTED); | |
435 | + // Fill with results | |
436 | + for (int i = 0; i < permissions.length; i++) | |
437 | + perms.put(permissions[i], grantResults[i]); | |
438 | + // Check for ACCESS_FINE_LOCATION | |
439 | + if (perms.get(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { | |
440 | + // Permission Denied | |
441 | + CAN_WRITE_EXTERNAL_STORAGE = false; | |
442 | + Toast.makeText(this, "禁用图片权限将导致发送图片功能无法使用!", Toast.LENGTH_SHORT) | |
443 | + .show(); | |
444 | + } | |
445 | + if (perms.get(Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { | |
446 | + CAN_RECORD_AUDIO = false; | |
447 | + Toast.makeText(this, "禁用录制音频权限将导致语音功能无法使用!", Toast.LENGTH_SHORT) | |
448 | + .show(); | |
449 | + } | |
450 | + break; | |
451 | + default: | |
452 | + super.onRequestPermissionsResult(requestCode, permissions, grantResults); | |
453 | + } | |
454 | + } | |
455 | + | |
456 | + public void setTitle(CharSequence title) { | |
457 | + ((TextView) getActionBar().getCustomView().findViewById(R.id.tvTitle)).setText(title); | |
458 | + } | |
459 | + | |
460 | + protected void showLeft(boolean flag) { | |
461 | + if (getActionBar() == null) { | |
462 | + return; | |
463 | + } | |
464 | + getActionBar().getCustomView().findViewById(R.id.ivLeft).setVisibility(flag ? View.VISIBLE : View.GONE); | |
465 | + } | |
466 | + | |
467 | + protected void showRight(boolean flag) { | |
468 | + if (getActionBar() == null) { | |
469 | + return; | |
470 | + } | |
471 | + getActionBar().getCustomView().findViewById(R.id.llRight).setVisibility(flag ? View.VISIBLE : View.GONE); | |
472 | + } | |
473 | + | |
474 | + protected void doLeft() { | |
475 | + finish(); | |
476 | + } | |
477 | + | |
478 | + protected void doRight() { | |
479 | + | |
480 | + } | |
481 | + | |
482 | + protected void setRight(int drawRes) { | |
483 | + if (getActionBar() == null) { | |
484 | + return; | |
485 | + } | |
486 | + ((ImageView) getActionBar().getCustomView().findViewById(R.id.ivRight)).setImageResource(drawRes); | |
487 | + getActionBar().getCustomView().findViewById(R.id.ivRight).setVisibility(View.VISIBLE); | |
488 | + } | |
489 | + | |
490 | + protected void setRightText(String text){ | |
491 | + if(getActionBar()==null){ | |
492 | + return; | |
493 | + } | |
494 | + ((TextView)getActionBar().getCustomView().findViewById(R.id.tvRight)).setText(text); | |
495 | + getActionBar().getCustomView().findViewById(R.id.tvRight).setVisibility(View.VISIBLE); | |
496 | + } | |
497 | + | |
498 | + /** | |
499 | + * 常用语列表初始化 | |
500 | + */ | |
501 | + @SuppressLint({"NewApi", "InflateParams"}) | |
502 | + private void initpop() { | |
503 | + mess_lv = (ListView) findViewById(R.id.mess_lv); | |
504 | + adapter = new DataAdapter(this, item); | |
505 | + mess_lv.setAdapter(adapter); | |
506 | + } | |
507 | + | |
508 | + private void downLoad() { | |
509 | + if (!isDown) { | |
510 | + new Thread(new Runnable() { | |
511 | + | |
512 | + @Override | |
513 | + public void run() { | |
514 | + // TODO Auto-generated method stub | |
515 | + loadRecords(); | |
516 | + } | |
517 | + }).start(); | |
518 | + } | |
519 | + } | |
520 | + | |
521 | + | |
522 | + @Override | |
523 | + protected void onActivityResult(int requestCode, int resultCode, Intent data) { | |
524 | + super.onActivityResult(requestCode, resultCode, data); | |
525 | + if (resultCode == RESULT_OK) { | |
526 | + tbbv.setVisibility(View.GONE); | |
527 | + mess_iv.setBackgroundResource(R.mipmap.tb_more); | |
528 | + switch (requestCode) { | |
529 | + case ChatBottomView.FROM_CAMERA: | |
530 | + FileInputStream is = null; | |
531 | + try { | |
532 | + is = new FileInputStream(camPicPath); | |
533 | + File camFile = new File(camPicPath); // 图片文件路径 | |
534 | + if (camFile.exists()) { | |
535 | + int size = ImageCheckoutUtil | |
536 | + .getImageSize(ImageCheckoutUtil | |
537 | + .getLoacalBitmap(camPicPath)); | |
538 | + if (size > IMAGE_SIZE) { | |
539 | + showDialog(camPicPath); | |
540 | + } else { | |
541 | + sendImage(camPicPath); | |
542 | + } | |
543 | + } else { | |
544 | + showToast("该文件不存在!"); | |
545 | + } | |
546 | + } catch (FileNotFoundException e) { | |
547 | + // TODO Auto-generated catch block | |
548 | + e.printStackTrace(); | |
549 | + } finally { | |
550 | + // 关闭流 | |
551 | + try { | |
552 | + is.close(); | |
553 | + } catch (IOException e) { | |
554 | + // TODO Auto-generated catch block | |
555 | + e.printStackTrace(); | |
556 | + } | |
557 | + } | |
558 | + break; | |
559 | + case ChatBottomView.FROM_GALLERY: | |
560 | + Uri uri = data.getData(); | |
561 | + String path = FileSaveUtil.getPath(getApplicationContext(), uri); | |
562 | + mCurrentPhotoFile = new File(path); // 图片文件路径 | |
563 | + if (mCurrentPhotoFile.exists()) { | |
564 | + int size = ImageCheckoutUtil.getImageSize(ImageCheckoutUtil.getLoacalBitmap(path)); | |
565 | + if (size > IMAGE_SIZE) { | |
566 | + showDialog(path); | |
567 | + } else { | |
568 | + sendImage(path); | |
569 | + } | |
570 | + } else { | |
571 | + showToast("该文件不存在!"); | |
572 | + } | |
573 | + | |
574 | + break; | |
575 | + } | |
576 | + } else if (resultCode == RESULT_CANCELED) { | |
577 | + // Toast.makeText(this, "操作取消", Toast.LENGTH_SHORT).show(); | |
578 | + } | |
579 | + } | |
580 | + | |
581 | + @Override | |
582 | + public boolean onKeyDown(int keyCode, KeyEvent event) { | |
583 | + if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) { | |
584 | + finish(); | |
585 | + return true; | |
586 | + } | |
587 | + return super.onKeyDown(keyCode, event); | |
588 | + } | |
589 | + | |
590 | + /** | |
591 | + * 界面复位 | |
592 | + */ | |
593 | + protected void reset() { | |
594 | + emoji_group.setVisibility(View.GONE); | |
595 | + tbbv.setVisibility(View.GONE); | |
596 | + mess_lv.setVisibility(View.GONE); | |
597 | + emoji.setBackgroundResource(R.mipmap.emoji); | |
598 | + mess_iv.setBackgroundResource(R.mipmap.tb_more); | |
599 | + voiceIv.setBackgroundResource(R.mipmap.voice_btn_normal); | |
600 | + } | |
601 | + | |
602 | + public void showToast(String text) { | |
603 | + if (mToast == null) { | |
604 | + mToast = Toast.makeText(this, text, Toast.LENGTH_SHORT); | |
605 | + } else { | |
606 | + mToast.setText(text); | |
607 | + mToast.setDuration(Toast.LENGTH_SHORT); | |
608 | + } | |
609 | + mToast.show(); | |
610 | + } | |
611 | + | |
612 | + public void cancelToast() { | |
613 | + if (mToast != null) { | |
614 | + mToast.cancel(); | |
615 | + } | |
616 | + } | |
617 | + | |
618 | + | |
619 | + /** | |
620 | + * 获取表情的gridview的子view | |
621 | + * | |
622 | + * @param i | |
623 | + * @return | |
624 | + */ | |
625 | + private View getGridChildView(int i) { | |
626 | + View view = View.inflate(this, R.layout.layout_expression_gridview, null); | |
627 | + ExpandGridView gv = (ExpandGridView) view.findViewById(R.id.gridview); | |
628 | + List<String> list = new ArrayList<String>(); | |
629 | + if (i == 1) { | |
630 | + List<String> list1 = reslist.subList(0, 20); | |
631 | + list.addAll(list1); | |
632 | + } else if (i == 2) { | |
633 | + list.addAll(reslist.subList(20, reslist.size())); | |
634 | + } | |
635 | + list.add("delete_expression"); | |
636 | + final ExpressionAdapter expressionAdapter = new ExpressionAdapter(this, | |
637 | + 1, list); | |
638 | + gv.setAdapter(expressionAdapter); | |
639 | + gv.setOnItemClickListener(new AdapterView.OnItemClickListener() { | |
640 | + | |
641 | + @Override | |
642 | + public void onItemClick(AdapterView<?> parent, View view, | |
643 | + int position, long id) { | |
644 | + String filename = expressionAdapter.getItem(position); | |
645 | + try { | |
646 | + // 文字输入框可见时,才可输入表情 | |
647 | + // 按住说话可见,不让输入表情 | |
648 | + if (filename != "delete_expression") { // 不是删除键,显示表情 | |
649 | + // 这里用的反射,所以混淆的时候不要混淆SmileUtils这个类 | |
650 | + @SuppressWarnings("rawtypes") | |
651 | + Class clz = Class | |
652 | + .forName("com.maxi.chatdemo.utils.SmileUtils"); | |
653 | + Field field = clz.getField(filename); | |
654 | + String oriContent = mEditTextContent.getText() | |
655 | + .toString(); | |
656 | + int index = Math.max( | |
657 | + mEditTextContent.getSelectionStart(), 0); | |
658 | + StringBuilder sBuilder = new StringBuilder(oriContent); | |
659 | + Spannable insertEmotion = SmileUtils.getSmiledText( | |
660 | + BaseActivity.this, | |
661 | + (String) field.get(null)); | |
662 | + sBuilder.insert(index, insertEmotion); | |
663 | + mEditTextContent.setText(sBuilder.toString()); | |
664 | + mEditTextContent.setSelection(index | |
665 | + + insertEmotion.length()); | |
666 | + } else { // 删除文字或者表情 | |
667 | + if (!TextUtils.isEmpty(mEditTextContent.getText())) { | |
668 | + | |
669 | + int selectionStart = mEditTextContent | |
670 | + .getSelectionStart();// 获取光标的位置 | |
671 | + if (selectionStart > 0) { | |
672 | + String body = mEditTextContent.getText() | |
673 | + .toString(); | |
674 | + String tempStr = body.substring(0, | |
675 | + selectionStart); | |
676 | + int i = tempStr.lastIndexOf("[");// 获取最后一个表情的位置 | |
677 | + if (i != -1) { | |
678 | + CharSequence cs = tempStr.substring(i, | |
679 | + selectionStart); | |
680 | + if (SmileUtils.containsKey(cs.toString())) | |
681 | + mEditTextContent.getEditableText() | |
682 | + .delete(i, selectionStart); | |
683 | + else | |
684 | + mEditTextContent.getEditableText() | |
685 | + .delete(selectionStart - 1, | |
686 | + selectionStart); | |
687 | + } else { | |
688 | + mEditTextContent.getEditableText().delete( | |
689 | + selectionStart - 1, selectionStart); | |
690 | + } | |
691 | + } | |
692 | + } | |
693 | + | |
694 | + } | |
695 | + } catch (Exception e) { | |
696 | + } | |
697 | + | |
698 | + } | |
699 | + }); | |
700 | + return view; | |
701 | + } | |
702 | + | |
703 | + public List<String> getExpressionRes(int getSum) { | |
704 | + List<String> reslist = new ArrayList<String>(); | |
705 | + for (int x = 1; x <= getSum; x++) { | |
706 | + String filename = "f" + x; | |
707 | + reslist.add(filename); | |
708 | + } | |
709 | + return reslist; | |
710 | + | |
711 | + } | |
712 | + | |
713 | + private void showDialog(final String path) { | |
714 | + new Thread(new Runnable() { | |
715 | + | |
716 | + @Override | |
717 | + public void run() { | |
718 | + // // TODO Auto-generated method stub | |
719 | + try { | |
720 | + String GalPicPath = getSavePicPath(); | |
721 | + Bitmap bitmap = PictureUtil.compressSizeImage(path); | |
722 | + boolean isSave = FileSaveUtil.saveBitmap( | |
723 | + PictureUtil.reviewPicRotate(bitmap, GalPicPath), | |
724 | + GalPicPath); | |
725 | + File file = new File(GalPicPath); | |
726 | + if (file.exists() && isSave) { | |
727 | + sendImage(GalPicPath); | |
728 | + } | |
729 | + } catch (Exception e) { | |
730 | + e.printStackTrace(); | |
731 | + } | |
732 | + } | |
733 | + }).start(); | |
734 | + } | |
735 | + | |
736 | + | |
737 | + private String getSavePicPath() { | |
738 | + final String dir = FileSaveUtil.SD_CARD_PATH + "image_data/"; | |
739 | + try { | |
740 | + FileSaveUtil.createSDDirectory(dir); | |
741 | + } catch (IOException e) { | |
742 | + // TODO Auto-generated catch block | |
743 | + e.printStackTrace(); | |
744 | + } | |
745 | + String fileName = String.valueOf(System.currentTimeMillis() + ".png"); | |
746 | + return dir + fileName; | |
747 | + } | |
748 | + | |
749 | + public ChatMessageBean getTbub(String username, int type, | |
750 | + String Content, String imageIconUrl, String imageUrl, | |
751 | + String imageLocal, String userVoicePath, String userVoiceUrl, | |
752 | + Float userVoiceTime, @ChatConst.SendState int sendState) { | |
753 | + ChatMessageBean tbub = new ChatMessageBean(); | |
754 | + tbub.setUserName(username); | |
755 | + String time = returnTime(); | |
756 | + tbub.setTime(time); | |
757 | + tbub.setType(type); | |
758 | + tbub.setUserContent(Content); | |
759 | + tbub.setImageIconUrl(imageIconUrl); | |
760 | + tbub.setImageUrl(imageUrl); | |
761 | + tbub.setUserVoicePath(userVoicePath); | |
762 | + tbub.setUserVoiceUrl(userVoiceUrl); | |
763 | + tbub.setUserVoiceTime(userVoiceTime); | |
764 | + tbub.setSendState(sendState); | |
765 | + tbub.setImageLocal(imageLocal); | |
766 | + mChatDbManager.insert(tbub); | |
767 | + | |
768 | + return tbub; | |
769 | + } | |
770 | + | |
771 | + private View.OnKeyListener onKeyListener = new View.OnKeyListener() { | |
772 | + | |
773 | + @Override | |
774 | + public boolean onKey(View v, int keyCode, KeyEvent event) { | |
775 | + if (keyCode == KeyEvent.KEYCODE_ENTER | |
776 | + && event.getAction() == KeyEvent.ACTION_DOWN) { | |
777 | + sendMessage(); | |
778 | + return true; | |
779 | + } | |
780 | + return false; | |
781 | + } | |
782 | + }; | |
783 | + | |
784 | + @SuppressLint("SimpleDateFormat") | |
785 | + public static String returnTime() { | |
786 | + SimpleDateFormat sDateFormat = new SimpleDateFormat( | |
787 | + "yyyy-MM-dd HH:mm:ss"); | |
788 | + String date = sDateFormat.format(new java.util.Date()); | |
789 | + return date; | |
790 | + } | |
791 | +} | ... | ... |
... | ... | @@ -0,0 +1,63 @@ |
1 | +package com.shunzhi.mychartlibrary.adapter; | |
2 | + | |
3 | +import android.annotation.SuppressLint; | |
4 | +import android.content.Context; | |
5 | +import android.view.LayoutInflater; | |
6 | +import android.view.View; | |
7 | +import android.view.ViewGroup; | |
8 | +import android.widget.BaseAdapter; | |
9 | +import android.widget.TextView; | |
10 | + | |
11 | +import com.shunzhi.mychartlibrary.R; | |
12 | + | |
13 | + | |
14 | +public class DataAdapter extends BaseAdapter { | |
15 | + | |
16 | + private String[] title; | |
17 | + private Context context; | |
18 | + public DataAdapter(Context context,String[] title) { | |
19 | + super(); | |
20 | + this.context = context; | |
21 | + this.title = title; | |
22 | + } | |
23 | + | |
24 | + @Override | |
25 | + public int getCount() { | |
26 | + return title.length; | |
27 | + } | |
28 | + | |
29 | + @Override | |
30 | + public Object getItem(int position) { | |
31 | + return title[position]; | |
32 | + } | |
33 | + | |
34 | + @Override | |
35 | + public long getItemId(int position) { | |
36 | + return position; | |
37 | + } | |
38 | + | |
39 | + @SuppressLint("InflateParams") | |
40 | + @Override | |
41 | + public View getView(final int position, View convertView, | |
42 | + ViewGroup parent) { | |
43 | + ViewHolder holder; | |
44 | + if (convertView == null) { | |
45 | + holder = new ViewHolder(); | |
46 | + convertView = LayoutInflater.from(context) | |
47 | + .inflate(R.layout.layout_mess_iv_listitem, null); | |
48 | + holder.money_Tv = (TextView) convertView | |
49 | + .findViewById(R.id.title); | |
50 | + convertView.setTag(holder); | |
51 | + } else { | |
52 | + holder = (ViewHolder) convertView.getTag(); | |
53 | + } | |
54 | + | |
55 | + holder.money_Tv.setText(title[position]); | |
56 | + return convertView; | |
57 | + } | |
58 | + | |
59 | + class ViewHolder { | |
60 | + | |
61 | + TextView money_Tv; | |
62 | + } | |
63 | +} | ... | ... |
... | ... | @@ -0,0 +1,49 @@ |
1 | +/** | |
2 | + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
8 | + * Unless required by applicable law or agreed to in writing, software | |
9 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
10 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
11 | + * See the License for the specific language governing permissions and | |
12 | + * limitations under the License. | |
13 | + */ | |
14 | +package com.shunzhi.mychartlibrary.adapter; | |
15 | + | |
16 | +import android.content.Context; | |
17 | +import android.view.View; | |
18 | +import android.view.ViewGroup; | |
19 | +import android.widget.ArrayAdapter; | |
20 | +import android.widget.ImageView; | |
21 | + | |
22 | + | |
23 | +import com.shunzhi.mychartlibrary.R; | |
24 | + | |
25 | +import java.util.List; | |
26 | + | |
27 | +public class ExpressionAdapter extends ArrayAdapter<String>{ | |
28 | + | |
29 | + public ExpressionAdapter(Context context, int textViewResourceId, List<String> objects) { | |
30 | + super(context, textViewResourceId, objects); | |
31 | + } | |
32 | + | |
33 | + | |
34 | + @Override | |
35 | + public View getView(int position, View convertView, ViewGroup parent) { | |
36 | + if(convertView == null){ | |
37 | + convertView = View.inflate(getContext(), R.layout.layout_row_expression, null); | |
38 | + } | |
39 | + | |
40 | + ImageView imageView = (ImageView) convertView.findViewById(R.id.iv_expression); | |
41 | + | |
42 | + String filename = getItem(position); | |
43 | + int resId = getContext().getResources().getIdentifier(filename, "mipmap", getContext().getPackageName()); | |
44 | + imageView.setImageResource(resId); | |
45 | + | |
46 | + return convertView; | |
47 | + } | |
48 | + | |
49 | +} | ... | ... |
... | ... | @@ -0,0 +1,52 @@ |
1 | +/** | |
2 | + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
8 | + * Unless required by applicable law or agreed to in writing, software | |
9 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
10 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
11 | + * See the License for the specific language governing permissions and | |
12 | + * limitations under the License. | |
13 | + */ | |
14 | +package com.shunzhi.mychartlibrary.adapter; | |
15 | + | |
16 | +import android.support.v4.view.PagerAdapter; | |
17 | +import android.support.v4.view.ViewPager; | |
18 | +import android.view.View; | |
19 | + | |
20 | +import java.util.List; | |
21 | + | |
22 | +public class ExpressionPagerAdapter extends PagerAdapter { | |
23 | + | |
24 | + private List<View> views; | |
25 | + | |
26 | + public ExpressionPagerAdapter(List<View> views) { | |
27 | + this.views = views; | |
28 | + } | |
29 | + | |
30 | + @Override | |
31 | + public int getCount() { | |
32 | + return views.size(); | |
33 | + } | |
34 | + | |
35 | + @Override | |
36 | + public boolean isViewFromObject(View arg0, Object arg1) { | |
37 | + return arg0 == arg1; | |
38 | + } | |
39 | + | |
40 | + @Override | |
41 | + public Object instantiateItem(View arg0, int arg1) { | |
42 | + ((ViewPager) arg0).addView(views.get(arg1)); | |
43 | + return views.get(arg1); | |
44 | + } | |
45 | + | |
46 | + @Override | |
47 | + public void destroyItem(View arg0, int arg1, Object arg2) { | |
48 | + ((ViewPager) arg0).removeView(views.get(arg1)); | |
49 | + | |
50 | + } | |
51 | + | |
52 | +} | ... | ... |
... | ... | @@ -0,0 +1,607 @@ |
1 | +package com.shunzhi.mychartlibrary.animator; | |
2 | + | |
3 | +import android.support.v4.view.ViewCompat; | |
4 | +import android.support.v4.view.ViewPropertyAnimatorCompat; | |
5 | +import android.support.v4.view.ViewPropertyAnimatorListener; | |
6 | +import android.support.v7.widget.RecyclerView; | |
7 | +import android.support.v7.widget.SimpleItemAnimator; | |
8 | +import android.view.View; | |
9 | + | |
10 | +import java.util.ArrayList; | |
11 | +import java.util.List; | |
12 | + | |
13 | + | |
14 | +/** | |
15 | + * Created by Mao Jiqing on 2016/9/30. | |
16 | + */ | |
17 | +public abstract class BaseItemAnimator extends SimpleItemAnimator { | |
18 | + | |
19 | + /** | |
20 | + * RecyclerView | |
21 | + */ | |
22 | + protected RecyclerView mRecyclerView; | |
23 | + | |
24 | + //------------------------------------------------------------ | |
25 | + // Constructor | |
26 | + //------------------------------------------------------------ | |
27 | + | |
28 | + public BaseItemAnimator(RecyclerView recyclerView){ | |
29 | + mRecyclerView = recyclerView; | |
30 | + } | |
31 | + | |
32 | + //------------------------------------------------------------ | |
33 | + // Default Item Animator | |
34 | + //------------------------------------------------------------ | |
35 | + private static final boolean DEBUG = false; | |
36 | + | |
37 | + private ArrayList<RecyclerView.ViewHolder> mPendingRemovals = new ArrayList<>(); | |
38 | + private ArrayList<RecyclerView.ViewHolder> mPendingAdditions = new ArrayList<>(); | |
39 | + private ArrayList<MoveInfo> mPendingMoves = new ArrayList<>(); | |
40 | + private ArrayList<ChangeInfo> mPendingChanges = new ArrayList<>(); | |
41 | + | |
42 | + private ArrayList<ArrayList<RecyclerView.ViewHolder>> mAdditionsList = new ArrayList<>(); | |
43 | + private ArrayList<ArrayList<MoveInfo>> mMovesList = new ArrayList<>(); | |
44 | + private ArrayList<ArrayList<ChangeInfo>> mChangesList = new ArrayList<>(); | |
45 | + | |
46 | + protected ArrayList<RecyclerView.ViewHolder> mAddAnimations = new ArrayList<>(); | |
47 | + protected ArrayList<RecyclerView.ViewHolder> mMoveAnimations = new ArrayList<>(); | |
48 | + protected ArrayList<RecyclerView.ViewHolder> mRemoveAnimations = new ArrayList<>(); | |
49 | + protected ArrayList<RecyclerView.ViewHolder> mChangeAnimations = new ArrayList<>(); | |
50 | + | |
51 | + private static class MoveInfo { | |
52 | + public RecyclerView.ViewHolder holder; | |
53 | + public int fromX, fromY, toX, toY; | |
54 | + | |
55 | + private MoveInfo(RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) { | |
56 | + this.holder = holder; | |
57 | + this.fromX = fromX; | |
58 | + this.fromY = fromY; | |
59 | + this.toX = toX; | |
60 | + this.toY = toY; | |
61 | + } | |
62 | + } | |
63 | + | |
64 | + private static class ChangeInfo { | |
65 | + public RecyclerView.ViewHolder oldHolder, newHolder; | |
66 | + public int fromX, fromY, toX, toY; | |
67 | + private ChangeInfo(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder) { | |
68 | + this.oldHolder = oldHolder; | |
69 | + this.newHolder = newHolder; | |
70 | + } | |
71 | + | |
72 | + private ChangeInfo(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, | |
73 | + int fromX, int fromY, int toX, int toY) { | |
74 | + this(oldHolder, newHolder); | |
75 | + this.fromX = fromX; | |
76 | + this.fromY = fromY; | |
77 | + this.toX = toX; | |
78 | + this.toY = toY; | |
79 | + } | |
80 | + | |
81 | + @Override | |
82 | + public String toString() { | |
83 | + return "ChangeInfo{" + | |
84 | + "oldHolder=" + oldHolder + | |
85 | + ", newHolder=" + newHolder + | |
86 | + ", fromX=" + fromX + | |
87 | + ", fromY=" + fromY + | |
88 | + ", toX=" + toX + | |
89 | + ", toY=" + toY + | |
90 | + '}'; | |
91 | + } | |
92 | + } | |
93 | + | |
94 | + | |
95 | + @Override | |
96 | + public void runPendingAnimations() { | |
97 | + boolean removalsPending = !mPendingRemovals.isEmpty(); | |
98 | + boolean movesPending = !mPendingMoves.isEmpty(); | |
99 | + boolean changesPending = !mPendingChanges.isEmpty(); | |
100 | + boolean additionsPending = !mPendingAdditions.isEmpty(); | |
101 | + if (!removalsPending && !movesPending && !additionsPending && !changesPending) { | |
102 | + // nothing to animate | |
103 | + return; | |
104 | + } | |
105 | + // First, remove stuff | |
106 | + for (RecyclerView.ViewHolder holder : mPendingRemovals) { | |
107 | + animateRemoveImpl(holder); | |
108 | + } | |
109 | + mPendingRemovals.clear(); | |
110 | + // Next, move stuff | |
111 | + if (movesPending) { | |
112 | + final ArrayList<MoveInfo> moves = new ArrayList<>(); | |
113 | + moves.addAll(mPendingMoves); | |
114 | + mMovesList.add(moves); | |
115 | + mPendingMoves.clear(); | |
116 | + Runnable mover = new Runnable() { | |
117 | + @Override | |
118 | + public void run() { | |
119 | + for (MoveInfo moveInfo : moves) { | |
120 | + animateMoveImpl(moveInfo.holder, moveInfo.fromX, moveInfo.fromY, | |
121 | + moveInfo.toX, moveInfo.toY); | |
122 | + } | |
123 | + moves.clear(); | |
124 | + mMovesList.remove(moves); | |
125 | + } | |
126 | + }; | |
127 | + if (removalsPending) { | |
128 | + View view = moves.get(0).holder.itemView; | |
129 | + ViewCompat.postOnAnimationDelayed(view, mover, getRemoveDuration()); | |
130 | + } else { | |
131 | + mover.run(); | |
132 | + } | |
133 | + } | |
134 | + // Next, change stuff, to run in parallel with move animations | |
135 | + if (changesPending) { | |
136 | + final ArrayList<ChangeInfo> changes = new ArrayList<>(); | |
137 | + changes.addAll(mPendingChanges); | |
138 | + mChangesList.add(changes); | |
139 | + mPendingChanges.clear(); | |
140 | + Runnable changer = new Runnable() { | |
141 | + @Override | |
142 | + public void run() { | |
143 | + for (ChangeInfo change : changes) { | |
144 | + animateChangeImpl(change); | |
145 | + } | |
146 | + changes.clear(); | |
147 | + mChangesList.remove(changes); | |
148 | + } | |
149 | + }; | |
150 | + if (removalsPending) { | |
151 | + RecyclerView.ViewHolder holder = changes.get(0).oldHolder; | |
152 | + ViewCompat.postOnAnimationDelayed(holder.itemView, changer, getRemoveDuration()); | |
153 | + } else { | |
154 | + changer.run(); | |
155 | + } | |
156 | + } | |
157 | + // Next, add stuff | |
158 | + if (additionsPending) { | |
159 | + final ArrayList<RecyclerView.ViewHolder> additions = new ArrayList<>(); | |
160 | + additions.addAll(mPendingAdditions); | |
161 | + mAdditionsList.add(additions); | |
162 | + mPendingAdditions.clear(); | |
163 | + Runnable adder = new Runnable() { | |
164 | + public void run() { | |
165 | + for (RecyclerView.ViewHolder holder : additions) { | |
166 | + animateAddImpl(holder); | |
167 | + } | |
168 | + additions.clear(); | |
169 | + mAdditionsList.remove(additions); | |
170 | + } | |
171 | + }; | |
172 | + if (removalsPending || movesPending || changesPending) { | |
173 | + long removeDuration = removalsPending ? getRemoveDuration() : 0; | |
174 | + long moveDuration = movesPending ? getMoveDuration() : 0; | |
175 | + long changeDuration = changesPending ? getChangeDuration() : 0; | |
176 | + long totalDelay = removeDuration + Math.max(moveDuration, changeDuration); | |
177 | + View view = additions.get(0).itemView; | |
178 | + ViewCompat.postOnAnimationDelayed(view, adder, totalDelay); | |
179 | + } else { | |
180 | + adder.run(); | |
181 | + } | |
182 | + } | |
183 | + } | |
184 | + | |
185 | + @Override | |
186 | + public boolean animateAdd(final RecyclerView.ViewHolder holder) { | |
187 | + resetAnimation(holder); | |
188 | + prepareAnimateAdd(holder); | |
189 | + ViewCompat.setAlpha(holder.itemView, 0); | |
190 | + mPendingAdditions.add(holder); | |
191 | + return true; | |
192 | + } | |
193 | + | |
194 | + protected abstract void prepareAnimateAdd(final RecyclerView.ViewHolder holder); | |
195 | + | |
196 | + protected abstract void animateAddImpl(final RecyclerView.ViewHolder holder); | |
197 | + | |
198 | + @Override | |
199 | + public boolean animateRemove(final RecyclerView.ViewHolder holder) { | |
200 | + resetAnimation(holder); | |
201 | + mPendingRemovals.add(holder); | |
202 | + return true; | |
203 | + } | |
204 | + | |
205 | + protected abstract void animateRemoveImpl(final RecyclerView.ViewHolder holder); | |
206 | + | |
207 | + @Override | |
208 | + public boolean animateMove(final RecyclerView.ViewHolder holder, int fromX, int fromY, | |
209 | + int toX, int toY) { | |
210 | + final View view = holder.itemView; | |
211 | + fromX += ViewCompat.getTranslationX(holder.itemView); | |
212 | + fromY += ViewCompat.getTranslationY(holder.itemView); | |
213 | + resetAnimation(holder); | |
214 | + int deltaX = toX - fromX; | |
215 | + int deltaY = toY - fromY; | |
216 | + if (deltaX == 0 && deltaY == 0) { | |
217 | + dispatchMoveFinished(holder); | |
218 | + return false; | |
219 | + } | |
220 | + if (deltaX != 0) { | |
221 | + ViewCompat.setTranslationX(view, -deltaX); | |
222 | + } | |
223 | + if (deltaY != 0) { | |
224 | + ViewCompat.setTranslationY(view, -deltaY); | |
225 | + } | |
226 | + mPendingMoves.add(new MoveInfo(holder, fromX, fromY, toX, toY)); | |
227 | + return true; | |
228 | + } | |
229 | + | |
230 | + | |
231 | + private void animateMoveImpl(final RecyclerView.ViewHolder holder, int fromX, int fromY, int toX, int toY) { | |
232 | + final View view = holder.itemView; | |
233 | + final int deltaX = toX - fromX; | |
234 | + final int deltaY = toY - fromY; | |
235 | + if (deltaX != 0) { | |
236 | + ViewCompat.animate(view).translationX(0); | |
237 | + } | |
238 | + if (deltaY != 0) { | |
239 | + ViewCompat.animate(view).translationY(0); | |
240 | + } | |
241 | + // TODO: make EndActions end listeners instead, since end actions aren't called when | |
242 | + // vpas are canceled (and can't end them. why?) | |
243 | + // need listener functionality in VPACompat for this. Ick. | |
244 | + final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view); | |
245 | + mMoveAnimations.add(holder); | |
246 | + animation.setDuration(getMoveDuration()).setListener(new VpaListenerAdapter() { | |
247 | + @Override | |
248 | + public void onAnimationStart(View view) { | |
249 | + dispatchMoveStarting(holder); | |
250 | + } | |
251 | + @Override | |
252 | + public void onAnimationCancel(View view) { | |
253 | + if (deltaX != 0) { | |
254 | + ViewCompat.setTranslationX(view, 0); | |
255 | + } | |
256 | + if (deltaY != 0) { | |
257 | + ViewCompat.setTranslationY(view, 0); | |
258 | + } | |
259 | + } | |
260 | + @Override | |
261 | + public void onAnimationEnd(View view) { | |
262 | + animation.setListener(null); | |
263 | + dispatchMoveFinished(holder); | |
264 | + mMoveAnimations.remove(holder); | |
265 | + dispatchFinishedWhenDone(); | |
266 | + } | |
267 | + }).start(); | |
268 | + } | |
269 | + | |
270 | + @Override | |
271 | + public boolean animateChange(RecyclerView.ViewHolder oldHolder, RecyclerView.ViewHolder newHolder, | |
272 | + int fromX, int fromY, int toX, int toY) { | |
273 | + if (oldHolder == newHolder) { | |
274 | + // Don't know how to run change animations when the same view holder is re-used. | |
275 | + // run a move animation to handle position changes. | |
276 | + return animateMove(oldHolder, fromX, fromY, toX, toY); | |
277 | + } | |
278 | + final float prevTranslationX = ViewCompat.getTranslationX(oldHolder.itemView); | |
279 | + final float prevTranslationY = ViewCompat.getTranslationY(oldHolder.itemView); | |
280 | + final float prevAlpha = ViewCompat.getAlpha(oldHolder.itemView); | |
281 | + resetAnimation(oldHolder); | |
282 | + int deltaX = (int) (toX - fromX - prevTranslationX); | |
283 | + int deltaY = (int) (toY - fromY - prevTranslationY); | |
284 | + // recover prev translation state after ending animation | |
285 | + ViewCompat.setTranslationX(oldHolder.itemView, prevTranslationX); | |
286 | + ViewCompat.setTranslationY(oldHolder.itemView, prevTranslationY); | |
287 | + ViewCompat.setAlpha(oldHolder.itemView, prevAlpha); | |
288 | + if (newHolder != null) { | |
289 | + // carry over translation values | |
290 | + resetAnimation(newHolder); | |
291 | + ViewCompat.setTranslationX(newHolder.itemView, -deltaX); | |
292 | + ViewCompat.setTranslationY(newHolder.itemView, -deltaY); | |
293 | + ViewCompat.setAlpha(newHolder.itemView, 0); | |
294 | + } | |
295 | + mPendingChanges.add(new ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY)); | |
296 | + return true; | |
297 | + } | |
298 | + | |
299 | + private void animateChangeImpl(final ChangeInfo changeInfo) { | |
300 | + final RecyclerView.ViewHolder holder = changeInfo.oldHolder; | |
301 | + final View view = holder == null ? null : holder.itemView; | |
302 | + final RecyclerView.ViewHolder newHolder = changeInfo.newHolder; | |
303 | + final View newView = newHolder != null ? newHolder.itemView : null; | |
304 | + if (view != null) { | |
305 | + final ViewPropertyAnimatorCompat oldViewAnim = ViewCompat.animate(view).setDuration( | |
306 | + getChangeDuration()); | |
307 | + mChangeAnimations.add(changeInfo.oldHolder); | |
308 | + oldViewAnim.translationX(changeInfo.toX - changeInfo.fromX); | |
309 | + oldViewAnim.translationY(changeInfo.toY - changeInfo.fromY); | |
310 | + oldViewAnim.alpha(0).setListener(new VpaListenerAdapter() { | |
311 | + @Override | |
312 | + public void onAnimationStart(View view) { | |
313 | + dispatchChangeStarting(changeInfo.oldHolder, true); | |
314 | + } | |
315 | + | |
316 | + @Override | |
317 | + public void onAnimationEnd(View view) { | |
318 | + oldViewAnim.setListener(null); | |
319 | + ViewCompat.setAlpha(view, 1); | |
320 | + ViewCompat.setTranslationX(view, 0); | |
321 | + ViewCompat.setTranslationY(view, 0); | |
322 | + dispatchChangeFinished(changeInfo.oldHolder, true); | |
323 | + mChangeAnimations.remove(changeInfo.oldHolder); | |
324 | + dispatchFinishedWhenDone(); | |
325 | + } | |
326 | + }).start(); | |
327 | + } | |
328 | + if (newView != null) { | |
329 | + final ViewPropertyAnimatorCompat newViewAnimation = ViewCompat.animate(newView); | |
330 | + mChangeAnimations.add(changeInfo.newHolder); | |
331 | + newViewAnimation.translationX(0).translationY(0).setDuration(getChangeDuration()). | |
332 | + alpha(1).setListener(new VpaListenerAdapter() { | |
333 | + @Override | |
334 | + public void onAnimationStart(View view) { | |
335 | + dispatchChangeStarting(changeInfo.newHolder, false); | |
336 | + } | |
337 | + @Override | |
338 | + public void onAnimationEnd(View view) { | |
339 | + newViewAnimation.setListener(null); | |
340 | + ViewCompat.setAlpha(newView, 1); | |
341 | + ViewCompat.setTranslationX(newView, 0); | |
342 | + ViewCompat.setTranslationY(newView, 0); | |
343 | + dispatchChangeFinished(changeInfo.newHolder, false); | |
344 | + mChangeAnimations.remove(changeInfo.newHolder); | |
345 | + dispatchFinishedWhenDone(); | |
346 | + } | |
347 | + }).start(); | |
348 | + } | |
349 | + } | |
350 | + | |
351 | + private void endChangeAnimation(List<ChangeInfo> infoList, RecyclerView.ViewHolder item) { | |
352 | + for (int i = infoList.size() - 1; i >= 0; i--) { | |
353 | + ChangeInfo changeInfo = infoList.get(i); | |
354 | + if (endChangeAnimationIfNecessary(changeInfo, item)) { | |
355 | + if (changeInfo.oldHolder == null && changeInfo.newHolder == null) { | |
356 | + infoList.remove(changeInfo); | |
357 | + } | |
358 | + } | |
359 | + } | |
360 | + } | |
361 | + | |
362 | + private void endChangeAnimationIfNecessary(ChangeInfo changeInfo) { | |
363 | + if (changeInfo.oldHolder != null) { | |
364 | + endChangeAnimationIfNecessary(changeInfo, changeInfo.oldHolder); | |
365 | + } | |
366 | + if (changeInfo.newHolder != null) { | |
367 | + endChangeAnimationIfNecessary(changeInfo, changeInfo.newHolder); | |
368 | + } | |
369 | + } | |
370 | + private boolean endChangeAnimationIfNecessary(ChangeInfo changeInfo, RecyclerView.ViewHolder item) { | |
371 | + boolean oldItem = false; | |
372 | + if (changeInfo.newHolder == item) { | |
373 | + changeInfo.newHolder = null; | |
374 | + } else if (changeInfo.oldHolder == item) { | |
375 | + changeInfo.oldHolder = null; | |
376 | + oldItem = true; | |
377 | + } else { | |
378 | + return false; | |
379 | + } | |
380 | + ViewCompat.setAlpha(item.itemView, 1); | |
381 | + ViewCompat.setTranslationX(item.itemView, 0); | |
382 | + ViewCompat.setTranslationY(item.itemView, 0); | |
383 | + dispatchChangeFinished(item, oldItem); | |
384 | + return true; | |
385 | + } | |
386 | + | |
387 | + @Override | |
388 | + public void endAnimation(RecyclerView.ViewHolder item) { | |
389 | + final View view = item.itemView; | |
390 | + // this will trigger end callback which should set properties to their target values. | |
391 | + ViewCompat.animate(view).cancel(); | |
392 | + // TODO if some other animations are chained to end, how do we cancel them as well? | |
393 | + for (int i = mPendingMoves.size() - 1; i >= 0; i--) { | |
394 | + MoveInfo moveInfo = mPendingMoves.get(i); | |
395 | + if (moveInfo.holder == item) { | |
396 | + ViewCompat.setTranslationY(view, 0); | |
397 | + ViewCompat.setTranslationX(view, 0); | |
398 | + dispatchMoveFinished(item); | |
399 | + mPendingMoves.remove(i); | |
400 | + } | |
401 | + } | |
402 | + endChangeAnimation(mPendingChanges, item); | |
403 | + if (mPendingRemovals.remove(item)) { | |
404 | + ViewCompat.setAlpha(view, 1); | |
405 | + dispatchRemoveFinished(item); | |
406 | + } | |
407 | + if (mPendingAdditions.remove(item)) { | |
408 | + ViewCompat.setAlpha(view, 1); | |
409 | + dispatchAddFinished(item); | |
410 | + } | |
411 | + | |
412 | + for (int i = mChangesList.size() - 1; i >= 0; i--) { | |
413 | + ArrayList<ChangeInfo> changes = mChangesList.get(i); | |
414 | + endChangeAnimation(changes, item); | |
415 | + if (changes.isEmpty()) { | |
416 | + mChangesList.remove(i); | |
417 | + } | |
418 | + } | |
419 | + for (int i = mMovesList.size() - 1; i >= 0; i--) { | |
420 | + ArrayList<MoveInfo> moves = mMovesList.get(i); | |
421 | + for (int j = moves.size() - 1; j >= 0; j--) { | |
422 | + MoveInfo moveInfo = moves.get(j); | |
423 | + if (moveInfo.holder == item) { | |
424 | + ViewCompat.setTranslationY(view, 0); | |
425 | + ViewCompat.setTranslationX(view, 0); | |
426 | + dispatchMoveFinished(item); | |
427 | + moves.remove(j); | |
428 | + if (moves.isEmpty()) { | |
429 | + mMovesList.remove(i); | |
430 | + } | |
431 | + break; | |
432 | + } | |
433 | + } | |
434 | + } | |
435 | + for (int i = mAdditionsList.size() - 1; i >= 0; i--) { | |
436 | + ArrayList<RecyclerView.ViewHolder> additions = mAdditionsList.get(i); | |
437 | + if (additions.remove(item)) { | |
438 | + ViewCompat.setAlpha(view, 1); | |
439 | + dispatchAddFinished(item); | |
440 | + if (additions.isEmpty()) { | |
441 | + mAdditionsList.remove(i); | |
442 | + } | |
443 | + } | |
444 | + } | |
445 | + | |
446 | + // animations should be ended by the cancel above. | |
447 | + //noinspection PointlessBooleanExpression,ConstantConditions | |
448 | + if (mRemoveAnimations.remove(item) && DEBUG) { | |
449 | + throw new IllegalStateException("after animation is cancelled, item should not be in " | |
450 | + + "mRemoveAnimations list"); | |
451 | + } | |
452 | + | |
453 | + //noinspection PointlessBooleanExpression,ConstantConditions | |
454 | + if (mAddAnimations.remove(item) && DEBUG) { | |
455 | + throw new IllegalStateException("after animation is cancelled, item should not be in " | |
456 | + + "mAddAnimations list"); | |
457 | + } | |
458 | + | |
459 | + //noinspection PointlessBooleanExpression,ConstantConditions | |
460 | + if (mChangeAnimations.remove(item) && DEBUG) { | |
461 | + throw new IllegalStateException("after animation is cancelled, item should not be in " | |
462 | + + "mChangeAnimations list"); | |
463 | + } | |
464 | + | |
465 | + //noinspection PointlessBooleanExpression,ConstantConditions | |
466 | + if (mMoveAnimations.remove(item) && DEBUG) { | |
467 | + throw new IllegalStateException("after animation is cancelled, item should not be in " | |
468 | + + "mMoveAnimations list"); | |
469 | + } | |
470 | + dispatchFinishedWhenDone(); | |
471 | + } | |
472 | + | |
473 | + private void resetAnimation(RecyclerView.ViewHolder holder) { | |
474 | +// AnimatorCompatHelper.clearInterpolator(holder.itemView); | |
475 | + endAnimation(holder); | |
476 | + } | |
477 | + | |
478 | + @Override | |
479 | + public boolean isRunning() { | |
480 | + return (!mPendingAdditions.isEmpty() || | |
481 | + !mPendingChanges.isEmpty() || | |
482 | + !mPendingMoves.isEmpty() || | |
483 | + !mPendingRemovals.isEmpty() || | |
484 | + !mMoveAnimations.isEmpty() || | |
485 | + !mRemoveAnimations.isEmpty() || | |
486 | + !mAddAnimations.isEmpty() || | |
487 | + !mChangeAnimations.isEmpty() || | |
488 | + !mMovesList.isEmpty() || | |
489 | + !mAdditionsList.isEmpty() || | |
490 | + !mChangesList.isEmpty()); | |
491 | + } | |
492 | + | |
493 | + /** | |
494 | + * Check the state of currently pending and running animations. If there are none | |
495 | + * pending/running, call {@link #dispatchAnimationsFinished()} to notify any | |
496 | + * listeners. | |
497 | + */ | |
498 | + protected void dispatchFinishedWhenDone() { | |
499 | + if (!isRunning()) { | |
500 | + dispatchAnimationsFinished(); | |
501 | + } | |
502 | + } | |
503 | + | |
504 | + @Override | |
505 | + public void endAnimations() { | |
506 | + int count = mPendingMoves.size(); | |
507 | + for (int i = count - 1; i >= 0; i--) { | |
508 | + MoveInfo item = mPendingMoves.get(i); | |
509 | + View view = item.holder.itemView; | |
510 | + ViewCompat.setTranslationY(view, 0); | |
511 | + ViewCompat.setTranslationX(view, 0); | |
512 | + dispatchMoveFinished(item.holder); | |
513 | + mPendingMoves.remove(i); | |
514 | + } | |
515 | + count = mPendingRemovals.size(); | |
516 | + for (int i = count - 1; i >= 0; i--) { | |
517 | + RecyclerView.ViewHolder item = mPendingRemovals.get(i); | |
518 | + dispatchRemoveFinished(item); | |
519 | + mPendingRemovals.remove(i); | |
520 | + } | |
521 | + count = mPendingAdditions.size(); | |
522 | + for (int i = count - 1; i >= 0; i--) { | |
523 | + RecyclerView.ViewHolder item = mPendingAdditions.get(i); | |
524 | + View view = item.itemView; | |
525 | + ViewCompat.setAlpha(view, 1); | |
526 | + dispatchAddFinished(item); | |
527 | + mPendingAdditions.remove(i); | |
528 | + } | |
529 | + count = mPendingChanges.size(); | |
530 | + for (int i = count - 1; i >= 0; i--) { | |
531 | + endChangeAnimationIfNecessary(mPendingChanges.get(i)); | |
532 | + } | |
533 | + mPendingChanges.clear(); | |
534 | + if (!isRunning()) { | |
535 | + return; | |
536 | + } | |
537 | + | |
538 | + int listCount = mMovesList.size(); | |
539 | + for (int i = listCount - 1; i >= 0; i--) { | |
540 | + ArrayList<MoveInfo> moves = mMovesList.get(i); | |
541 | + count = moves.size(); | |
542 | + for (int j = count - 1; j >= 0; j--) { | |
543 | + MoveInfo moveInfo = moves.get(j); | |
544 | + RecyclerView.ViewHolder item = moveInfo.holder; | |
545 | + View view = item.itemView; | |
546 | + ViewCompat.setTranslationY(view, 0); | |
547 | + ViewCompat.setTranslationX(view, 0); | |
548 | + dispatchMoveFinished(moveInfo.holder); | |
549 | + moves.remove(j); | |
550 | + if (moves.isEmpty()) { | |
551 | + mMovesList.remove(moves); | |
552 | + } | |
553 | + } | |
554 | + } | |
555 | + listCount = mAdditionsList.size(); | |
556 | + for (int i = listCount - 1; i >= 0; i--) { | |
557 | + ArrayList<RecyclerView.ViewHolder> additions = mAdditionsList.get(i); | |
558 | + count = additions.size(); | |
559 | + for (int j = count - 1; j >= 0; j--) { | |
560 | + RecyclerView.ViewHolder item = additions.get(j); | |
561 | + View view = item.itemView; | |
562 | + ViewCompat.setAlpha(view, 1); | |
563 | + dispatchAddFinished(item); | |
564 | + additions.remove(j); | |
565 | + if (additions.isEmpty()) { | |
566 | + mAdditionsList.remove(additions); | |
567 | + } | |
568 | + } | |
569 | + } | |
570 | + listCount = mChangesList.size(); | |
571 | + for (int i = listCount - 1; i >= 0; i--) { | |
572 | + ArrayList<ChangeInfo> changes = mChangesList.get(i); | |
573 | + count = changes.size(); | |
574 | + for (int j = count - 1; j >= 0; j--) { | |
575 | + endChangeAnimationIfNecessary(changes.get(j)); | |
576 | + if (changes.isEmpty()) { | |
577 | + mChangesList.remove(changes); | |
578 | + } | |
579 | + } | |
580 | + } | |
581 | + | |
582 | + cancelAll(mRemoveAnimations); | |
583 | + cancelAll(mMoveAnimations); | |
584 | + cancelAll(mAddAnimations); | |
585 | + cancelAll(mChangeAnimations); | |
586 | + | |
587 | + dispatchAnimationsFinished(); | |
588 | + } | |
589 | + | |
590 | + void cancelAll(List<RecyclerView.ViewHolder> viewHolders) { | |
591 | + for (int i = viewHolders.size() - 1; i >= 0; i--) { | |
592 | + ViewCompat.animate(viewHolders.get(i).itemView).cancel(); | |
593 | + } | |
594 | + } | |
595 | + | |
596 | + | |
597 | + protected static class VpaListenerAdapter implements ViewPropertyAnimatorListener { | |
598 | + @Override | |
599 | + public void onAnimationStart(View view) {} | |
600 | + | |
601 | + @Override | |
602 | + public void onAnimationEnd(View view) {} | |
603 | + | |
604 | + @Override | |
605 | + public void onAnimationCancel(View view) {} | |
606 | + }; | |
607 | +} | |
0 | 608 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,91 @@ |
1 | +package com.shunzhi.mychartlibrary.animator; | |
2 | + | |
3 | +import android.support.v4.view.ViewCompat; | |
4 | +import android.support.v4.view.ViewPropertyAnimatorCompat; | |
5 | +import android.support.v7.widget.RecyclerView; | |
6 | +import android.view.View; | |
7 | + | |
8 | +/** | |
9 | + * Created by Mao Jiqing on 2016/9/30. | |
10 | + */ | |
11 | +public class SlideInOutBottomItemAnimator extends BaseItemAnimator { | |
12 | + | |
13 | + private float mOriginalY; | |
14 | + private float mDeltaY; | |
15 | + | |
16 | + public SlideInOutBottomItemAnimator(RecyclerView recyclerView) { | |
17 | + super(recyclerView); | |
18 | + } | |
19 | + | |
20 | + protected void animateRemoveImpl(final RecyclerView.ViewHolder holder) { | |
21 | + final View view = holder.itemView; | |
22 | + | |
23 | + final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view); | |
24 | + mRemoveAnimations.add(holder); | |
25 | + animation.setDuration(getRemoveDuration()) | |
26 | + .alpha(0) | |
27 | + .translationY(+mDeltaY) | |
28 | + .setListener(new VpaListenerAdapter() { | |
29 | + @Override | |
30 | + public void onAnimationStart(View view) { | |
31 | + dispatchRemoveStarting(holder); | |
32 | + } | |
33 | + | |
34 | + @Override | |
35 | + public void onAnimationEnd(View view) { | |
36 | + animation.setListener(null); | |
37 | + ViewCompat.setAlpha(view, 1); | |
38 | + ViewCompat.setTranslationY(view, +mDeltaY); | |
39 | + dispatchRemoveFinished(holder); | |
40 | + mRemoveAnimations.remove(holder); | |
41 | + dispatchFinishedWhenDone(); | |
42 | + } | |
43 | + }).start(); | |
44 | + } | |
45 | + | |
46 | + @Override | |
47 | + protected void prepareAnimateAdd(RecyclerView.ViewHolder holder) { | |
48 | + retrieveItemPosition(holder); | |
49 | + ViewCompat.setTranslationY(holder.itemView, +mDeltaY); | |
50 | + } | |
51 | + | |
52 | + protected void animateAddImpl(final RecyclerView.ViewHolder holder) { | |
53 | + final View view = holder.itemView; | |
54 | + | |
55 | + final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view); | |
56 | + mAddAnimations.add(holder); | |
57 | + animation.translationY(0) | |
58 | + .alpha(1) | |
59 | + .setDuration(getAddDuration()) | |
60 | + .setListener(new VpaListenerAdapter() { | |
61 | + @Override | |
62 | + public void onAnimationStart(View view) { | |
63 | + dispatchAddStarting(holder); | |
64 | + } | |
65 | + | |
66 | + @Override | |
67 | + public void onAnimationCancel(View view) { | |
68 | + ViewCompat.setAlpha(view, 1); | |
69 | + ViewCompat.setTranslationY(view, 0); | |
70 | + } | |
71 | + | |
72 | + @Override | |
73 | + public void onAnimationEnd(View view) { | |
74 | + animation.setListener(null); | |
75 | + ViewCompat.setAlpha(view, 1); | |
76 | + ViewCompat.setTranslationY(view, 0); | |
77 | + dispatchAddFinished(holder); | |
78 | + mAddAnimations.remove(holder); | |
79 | + dispatchFinishedWhenDone(); | |
80 | + } | |
81 | + }).start(); | |
82 | + } | |
83 | + | |
84 | + | |
85 | + private void retrieveItemPosition(final RecyclerView.ViewHolder holder) { | |
86 | + mOriginalY = mRecyclerView.getLayoutManager().getDecoratedTop(holder.itemView); | |
87 | + mDeltaY = mRecyclerView.getHeight() - mOriginalY; | |
88 | + } | |
89 | + | |
90 | + | |
91 | +} | |
0 | 92 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,23 @@ |
1 | +package com.shunzhi.mychartlibrary.common; | |
2 | + | |
3 | +import android.support.annotation.IntDef; | |
4 | + | |
5 | +import java.lang.annotation.Retention; | |
6 | +import java.lang.annotation.RetentionPolicy; | |
7 | + | |
8 | +/** | |
9 | + * Created by Mao Jiqing on 2016/10/15. | |
10 | + */ | |
11 | + | |
12 | +public class ChatConst { | |
13 | + public static final String LISTVIEW_DATABASE_NAME = "listview.db"; | |
14 | + public static final String RECYCLER_DATABASE_NAME = "recycler.db"; | |
15 | + public static final int SENDING = 0; | |
16 | + public static final int COMPLETED = 1; | |
17 | + public static final int SENDERROR = 2; | |
18 | + | |
19 | + @IntDef({SENDING, COMPLETED, SENDERROR}) | |
20 | + @Retention(RetentionPolicy.SOURCE) | |
21 | + public @interface SendState { | |
22 | + } | |
23 | +} | ... | ... |
... | ... | @@ -0,0 +1,355 @@ |
1 | +package com.shunzhi.mychartlibrary.db; | |
2 | + | |
3 | +import android.content.Context; | |
4 | +import android.database.sqlite.SQLiteDatabase; | |
5 | +import android.database.sqlite.SQLiteException; | |
6 | +import android.support.annotation.NonNull; | |
7 | +import android.support.annotation.Nullable; | |
8 | + | |
9 | + | |
10 | + | |
11 | +import org.greenrobot.greendao.AbstractDao; | |
12 | +import org.greenrobot.greendao.query.Query; | |
13 | +import org.greenrobot.greendao.query.QueryBuilder; | |
14 | + | |
15 | +import java.util.Collection; | |
16 | +import java.util.List; | |
17 | + | |
18 | +/** | |
19 | + * Created by Mao Jiqing on 2016/10/15. | |
20 | + */ | |
21 | + | |
22 | +public abstract class BaseManager<M, K> implements IDatabase<M, K> { | |
23 | + private static final String DEFAULT_DATABASE_NAME = "maxi.db"; | |
24 | + private static DaoMaster.DevOpenHelper mHelper; | |
25 | + protected static DaoSession daoSession; | |
26 | + | |
27 | + /** | |
28 | + * 初始化OpenHelper | |
29 | + * | |
30 | + * @param context | |
31 | + */ | |
32 | + public static void initOpenHelper(@NonNull Context context) { | |
33 | + mHelper = getOpenHelper(context, DEFAULT_DATABASE_NAME); | |
34 | + openWritableDb(); | |
35 | + } | |
36 | + | |
37 | + /** | |
38 | + * 初始化OpenHelper | |
39 | + * | |
40 | + * @param context | |
41 | + * @param dataBaseName | |
42 | + */ | |
43 | + public static void initOpenHelper(@NonNull Context context, @NonNull String dataBaseName) { | |
44 | + mHelper = getOpenHelper(context, dataBaseName); | |
45 | + openWritableDb(); | |
46 | + } | |
47 | + | |
48 | + /** | |
49 | + * Query for readable DB | |
50 | + */ | |
51 | + protected static void openReadableDb() throws SQLiteException { | |
52 | + daoSession = new DaoMaster(getReadableDatabase()).newSession(); | |
53 | + } | |
54 | + | |
55 | + /** | |
56 | + * Query for writable DB | |
57 | + */ | |
58 | + protected static void openWritableDb() throws SQLiteException { | |
59 | + daoSession = new DaoMaster(getWritableDatabase()).newSession(); | |
60 | + } | |
61 | + | |
62 | + private static SQLiteDatabase getWritableDatabase() { | |
63 | + return mHelper.getWritableDatabase(); | |
64 | + } | |
65 | + | |
66 | + private static SQLiteDatabase getReadableDatabase() { | |
67 | + return mHelper.getReadableDatabase(); | |
68 | + } | |
69 | + | |
70 | + /** | |
71 | + * 在applicaiton中初始化DatabaseHelper | |
72 | + */ | |
73 | + private static DaoMaster.DevOpenHelper getOpenHelper(@NonNull Context context, @Nullable String dataBaseName) { | |
74 | + closeDbConnections(); | |
75 | + return new DaoMaster.DevOpenHelper(context, dataBaseName, null); | |
76 | + } | |
77 | + | |
78 | + /** | |
79 | + * 只关闭helper就好,看源码就知道helper关闭的时候会关闭数据库 | |
80 | + */ | |
81 | + public static void closeDbConnections() { | |
82 | + if (mHelper != null) { | |
83 | + mHelper.close(); | |
84 | + mHelper = null; | |
85 | + } | |
86 | + if (daoSession != null) { | |
87 | + daoSession.clear(); | |
88 | + daoSession = null; | |
89 | + } | |
90 | + } | |
91 | + | |
92 | + @Override | |
93 | + public void clearDaoSession() { | |
94 | + if (daoSession != null) { | |
95 | + daoSession.clear(); | |
96 | + daoSession = null; | |
97 | + } | |
98 | + } | |
99 | + | |
100 | + @Override | |
101 | + public boolean dropDatabase() { | |
102 | + try { | |
103 | + openWritableDb(); | |
104 | + } catch (Exception e) { | |
105 | + return false; | |
106 | + } | |
107 | + return true; | |
108 | + } | |
109 | + | |
110 | + @Override | |
111 | + public boolean insert(@NonNull M m) { | |
112 | + try { | |
113 | + if (m == null) | |
114 | + return false; | |
115 | + openWritableDb(); | |
116 | + getAbstractDao().insert(m); | |
117 | + } catch (SQLiteException e) { | |
118 | + return false; | |
119 | + } | |
120 | + return true; | |
121 | + } | |
122 | + | |
123 | + @Override | |
124 | + public boolean insertOrReplace(@NonNull M m) { | |
125 | + try { | |
126 | + if (m == null) | |
127 | + return false; | |
128 | + openWritableDb(); | |
129 | + getAbstractDao().insertOrReplace(m); | |
130 | + } catch (SQLiteException e) { | |
131 | + return false; | |
132 | + } | |
133 | + return true; | |
134 | + } | |
135 | + | |
136 | + @Override | |
137 | + public boolean delete(@NonNull M m) { | |
138 | + try { | |
139 | + if (m == null) | |
140 | + return false; | |
141 | + openWritableDb(); | |
142 | + getAbstractDao().delete(m); | |
143 | + } catch (SQLiteException e) { | |
144 | + return false; | |
145 | + } | |
146 | + return true; | |
147 | + } | |
148 | + | |
149 | + @Override | |
150 | + public boolean deleteByKey(K key) { | |
151 | + try { | |
152 | + if (key.toString().isEmpty()) | |
153 | + return false; | |
154 | + openWritableDb(); | |
155 | + getAbstractDao().deleteByKey(key); | |
156 | + } catch (SQLiteException e) { | |
157 | + return false; | |
158 | + } | |
159 | + return true; | |
160 | + } | |
161 | + | |
162 | + @Override | |
163 | + public boolean deleteByKeyInTx(K... key) { | |
164 | + try { | |
165 | + openWritableDb(); | |
166 | + getAbstractDao().deleteByKeyInTx(key); | |
167 | + } catch (SQLiteException e) { | |
168 | + return false; | |
169 | + } | |
170 | + return true; | |
171 | + } | |
172 | + | |
173 | + @Override | |
174 | + public boolean deleteList(List<M> mList) { | |
175 | + try { | |
176 | + if (mList == null || mList.size() == 0) | |
177 | + return false; | |
178 | + openWritableDb(); | |
179 | + getAbstractDao().deleteInTx(mList); | |
180 | + } catch (SQLiteException e) { | |
181 | + return false; | |
182 | + } | |
183 | + return true; | |
184 | + } | |
185 | + | |
186 | + @Override | |
187 | + public boolean deleteAll() { | |
188 | + try { | |
189 | + openWritableDb(); | |
190 | + getAbstractDao().deleteAll(); | |
191 | + } catch (SQLiteException e) { | |
192 | + return false; | |
193 | + } | |
194 | + return true; | |
195 | + } | |
196 | + | |
197 | + @Override | |
198 | + public boolean update(@NonNull M m) { | |
199 | + try { | |
200 | + if (m == null) | |
201 | + return false; | |
202 | + openWritableDb(); | |
203 | + getAbstractDao().update(m); | |
204 | + } catch (SQLiteException e) { | |
205 | + return false; | |
206 | + } | |
207 | + return true; | |
208 | + } | |
209 | + | |
210 | + @Override | |
211 | + public boolean updateInTx(M... m) { | |
212 | + try { | |
213 | + if (m == null) | |
214 | + return false; | |
215 | + openWritableDb(); | |
216 | + getAbstractDao().updateInTx(m); | |
217 | + } catch (SQLiteException e) { | |
218 | + return false; | |
219 | + } | |
220 | + return true; | |
221 | + } | |
222 | + | |
223 | + @Override | |
224 | + public boolean updateList(List<M> mList) { | |
225 | + try { | |
226 | + if (mList == null || mList.size() == 0) | |
227 | + return false; | |
228 | + openWritableDb(); | |
229 | + getAbstractDao().updateInTx(mList); | |
230 | + } catch (SQLiteException e) { | |
231 | + return false; | |
232 | + } | |
233 | + return true; | |
234 | + } | |
235 | + | |
236 | + @Override | |
237 | + public M selectByPrimaryKey(@NonNull K key) { | |
238 | + try { | |
239 | + openReadableDb(); | |
240 | + return getAbstractDao().load(key); | |
241 | + } catch (SQLiteException e) { | |
242 | + return null; | |
243 | + } | |
244 | + } | |
245 | + | |
246 | + @Override | |
247 | + public List<M> loadAll() { | |
248 | + openReadableDb(); | |
249 | + return getAbstractDao().loadAll(); | |
250 | + } | |
251 | + | |
252 | + @Override | |
253 | + public List<M> loadPages(int page, int number) { | |
254 | + openReadableDb(); | |
255 | + return getAbstractDao().queryBuilder() | |
256 | + .offset(page * number).limit(number).list(); | |
257 | + } | |
258 | + | |
259 | + @Override | |
260 | + public long getPages(int number) { | |
261 | + long count = getAbstractDao().queryBuilder().count(); | |
262 | + long page = count / number; | |
263 | + if (page > 0 && count % number == 0) { | |
264 | + return page - 1; | |
265 | + } | |
266 | + return page; | |
267 | + } | |
268 | + | |
269 | + @Override | |
270 | + public boolean refresh(@NonNull M m) { | |
271 | + try { | |
272 | + if (m == null) | |
273 | + return false; | |
274 | + openWritableDb(); | |
275 | + getAbstractDao().refresh(m); | |
276 | + } catch (SQLiteException e) { | |
277 | + return false; | |
278 | + } | |
279 | + return true; | |
280 | + } | |
281 | + | |
282 | + @Override | |
283 | + public void runInTx(Runnable runnable) { | |
284 | + try { | |
285 | + openWritableDb(); | |
286 | + daoSession.runInTx(runnable); | |
287 | + } catch (SQLiteException e) { | |
288 | + } | |
289 | + } | |
290 | + | |
291 | + @Override | |
292 | + public boolean insertList(@NonNull List<M> list) { | |
293 | + try { | |
294 | + if (list == null || list.size() == 0) | |
295 | + return false; | |
296 | + openWritableDb(); | |
297 | + getAbstractDao().insertInTx(list); | |
298 | + } catch (SQLiteException e) { | |
299 | + return false; | |
300 | + } | |
301 | + return true; | |
302 | + } | |
303 | + | |
304 | + /** | |
305 | + * @param list | |
306 | + * @return | |
307 | + */ | |
308 | + @Override | |
309 | + public boolean insertOrReplaceList(@NonNull List<M> list) { | |
310 | + try { | |
311 | + if (list == null || list.size() == 0) | |
312 | + return false; | |
313 | + openWritableDb(); | |
314 | + getAbstractDao().insertOrReplaceInTx(list); | |
315 | + } catch (SQLiteException e) { | |
316 | + return false; | |
317 | + } | |
318 | + return true; | |
319 | + } | |
320 | + | |
321 | + @Override | |
322 | + public QueryBuilder<M> getQueryBuilder() { | |
323 | + openReadableDb(); | |
324 | + return getAbstractDao().queryBuilder(); | |
325 | + } | |
326 | + | |
327 | + /** | |
328 | + * @param where | |
329 | + * @param selectionArg | |
330 | + * @return | |
331 | + */ | |
332 | + @Override | |
333 | + public List<M> queryRaw(String where, String... selectionArg) { | |
334 | + openReadableDb(); | |
335 | + return getAbstractDao().queryRaw(where, selectionArg); | |
336 | + } | |
337 | + | |
338 | + public Query<M> queryRawCreate(String where, Object... selectionArg) { | |
339 | + openReadableDb(); | |
340 | + return getAbstractDao().queryRawCreate(where, selectionArg); | |
341 | + } | |
342 | + | |
343 | + public Query<M> queryRawCreateListArgs(String where, Collection<Object> selectionArg) { | |
344 | + openReadableDb(); | |
345 | + return getAbstractDao().queryRawCreateListArgs(where, selectionArg); | |
346 | + } | |
347 | + | |
348 | + /** | |
349 | + * 获取Dao | |
350 | + * | |
351 | + * @return | |
352 | + */ | |
353 | + public abstract AbstractDao<M, K> getAbstractDao(); | |
354 | + | |
355 | +} | ... | ... |
... | ... | @@ -0,0 +1,16 @@ |
1 | +package com.shunzhi.mychartlibrary.db; | |
2 | + | |
3 | + | |
4 | + | |
5 | +import org.greenrobot.greendao.AbstractDao; | |
6 | + | |
7 | +/** | |
8 | + * Created by Mao Jiqing on 2016/10/15. | |
9 | + */ | |
10 | + | |
11 | +public class ChatDbManager extends BaseManager<ChatMessageBean,Long> { | |
12 | + @Override | |
13 | + public AbstractDao<ChatMessageBean, Long> getAbstractDao() { | |
14 | + return BaseManager.daoSession.getChatMessageBeanDao(); | |
15 | + } | |
16 | +} | ... | ... |
... | ... | @@ -0,0 +1,194 @@ |
1 | +package com.shunzhi.mychartlibrary.db; | |
2 | + | |
3 | +/** | |
4 | + * Created by Mao Jiqing on 2016/10/15. | |
5 | + */ | |
6 | + | |
7 | + | |
8 | +import com.shunzhi.mychartlibrary.common.ChatConst; | |
9 | + | |
10 | +import org.greenrobot.greendao.annotation.Entity; | |
11 | +import org.greenrobot.greendao.annotation.Generated; | |
12 | +import org.greenrobot.greendao.annotation.Id; | |
13 | +import org.greenrobot.greendao.annotation.Property; | |
14 | + | |
15 | +@Entity | |
16 | +public class ChatMessageBean { | |
17 | + @Id | |
18 | + private Long id; | |
19 | + @Property(nameInDb = "UserId") | |
20 | + private String UserId; | |
21 | + @Property(nameInDb = "UserName") | |
22 | + private String UserName; | |
23 | + @Property(nameInDb = "UserHeadIcon") | |
24 | + private String UserHeadIcon; | |
25 | + @Property(nameInDb = "UserContent") | |
26 | + private String UserContent; | |
27 | + @Property(nameInDb = "time") | |
28 | + private String time; | |
29 | + @Property(nameInDb = "type") | |
30 | + private int type; | |
31 | + @Property(nameInDb = "messagetype") | |
32 | + private int messagetype; | |
33 | + @Property(nameInDb = "UserVoiceTime") | |
34 | + private float UserVoiceTime; | |
35 | + @Property(nameInDb = "UserVoicePath") | |
36 | + private String UserVoicePath; | |
37 | + @Property(nameInDb = "UserVoiceUrl") | |
38 | + private String UserVoiceUrl; | |
39 | + @Property(nameInDb = "sendState") | |
40 | + private @ChatConst.SendState int sendState; | |
41 | + @Property(nameInDb = "imageUrl") | |
42 | + private String imageUrl; | |
43 | + @Property(nameInDb = "imageIconUrl") | |
44 | + private String imageIconUrl; | |
45 | + @Property(nameInDb = "imageLocal") | |
46 | + private String imageLocal; | |
47 | + | |
48 | + @Generated(hash = 1463432601) | |
49 | + public ChatMessageBean(Long id, String UserId, String UserName, | |
50 | + String UserHeadIcon, String UserContent, String time, int type, | |
51 | + int messagetype, float UserVoiceTime, String UserVoicePath, | |
52 | + String UserVoiceUrl, int sendState, String imageUrl, | |
53 | + String imageIconUrl, String imageLocal) { | |
54 | + this.id = id; | |
55 | + this.UserId = UserId; | |
56 | + this.UserName = UserName; | |
57 | + this.UserHeadIcon = UserHeadIcon; | |
58 | + this.UserContent = UserContent; | |
59 | + this.time = time; | |
60 | + this.type = type; | |
61 | + this.messagetype = messagetype; | |
62 | + this.UserVoiceTime = UserVoiceTime; | |
63 | + this.UserVoicePath = UserVoicePath; | |
64 | + this.UserVoiceUrl = UserVoiceUrl; | |
65 | + this.sendState = sendState; | |
66 | + this.imageUrl = imageUrl; | |
67 | + this.imageIconUrl = imageIconUrl; | |
68 | + this.imageLocal = imageLocal; | |
69 | + } | |
70 | + | |
71 | + @Generated(hash = 1557449535) | |
72 | + public ChatMessageBean() { | |
73 | + } | |
74 | + | |
75 | + public Long getId() { | |
76 | + return this.id; | |
77 | + } | |
78 | + | |
79 | + public void setId(Long id) { | |
80 | + this.id = id; | |
81 | + } | |
82 | + | |
83 | + public String getUserId() { | |
84 | + return this.UserId; | |
85 | + } | |
86 | + | |
87 | + public void setUserId(String UserId) { | |
88 | + this.UserId = UserId; | |
89 | + } | |
90 | + | |
91 | + public String getUserName() { | |
92 | + return this.UserName; | |
93 | + } | |
94 | + | |
95 | + public void setUserName(String UserName) { | |
96 | + this.UserName = UserName; | |
97 | + } | |
98 | + | |
99 | + public String getUserHeadIcon() { | |
100 | + return this.UserHeadIcon; | |
101 | + } | |
102 | + | |
103 | + public void setUserHeadIcon(String UserHeadIcon) { | |
104 | + this.UserHeadIcon = UserHeadIcon; | |
105 | + } | |
106 | + | |
107 | + public String getUserContent() { | |
108 | + return this.UserContent; | |
109 | + } | |
110 | + | |
111 | + public void setUserContent(String UserContent) { | |
112 | + this.UserContent = UserContent; | |
113 | + } | |
114 | + | |
115 | + public String getTime() { | |
116 | + return this.time; | |
117 | + } | |
118 | + | |
119 | + public void setTime(String time) { | |
120 | + this.time = time; | |
121 | + } | |
122 | + | |
123 | + public int getType() { | |
124 | + return this.type; | |
125 | + } | |
126 | + | |
127 | + public void setType(int type) { | |
128 | + this.type = type; | |
129 | + } | |
130 | + | |
131 | + public int getMessagetype() { | |
132 | + return this.messagetype; | |
133 | + } | |
134 | + | |
135 | + public void setMessagetype(int messagetype) { | |
136 | + this.messagetype = messagetype; | |
137 | + } | |
138 | + | |
139 | + public float getUserVoiceTime() { | |
140 | + return this.UserVoiceTime; | |
141 | + } | |
142 | + | |
143 | + public void setUserVoiceTime(float UserVoiceTime) { | |
144 | + this.UserVoiceTime = UserVoiceTime; | |
145 | + } | |
146 | + | |
147 | + public String getUserVoicePath() { | |
148 | + return this.UserVoicePath; | |
149 | + } | |
150 | + | |
151 | + public void setUserVoicePath(String UserVoicePath) { | |
152 | + this.UserVoicePath = UserVoicePath; | |
153 | + } | |
154 | + | |
155 | + public String getUserVoiceUrl() { | |
156 | + return this.UserVoiceUrl; | |
157 | + } | |
158 | + | |
159 | + public void setUserVoiceUrl(String UserVoiceUrl) { | |
160 | + this.UserVoiceUrl = UserVoiceUrl; | |
161 | + } | |
162 | + | |
163 | + public int getSendState() { | |
164 | + return this.sendState; | |
165 | + } | |
166 | + | |
167 | + public void setSendState(int sendState) { | |
168 | + this.sendState = sendState; | |
169 | + } | |
170 | + | |
171 | + public String getImageUrl() { | |
172 | + return this.imageUrl; | |
173 | + } | |
174 | + | |
175 | + public void setImageUrl(String imageUrl) { | |
176 | + this.imageUrl = imageUrl; | |
177 | + } | |
178 | + | |
179 | + public String getImageIconUrl() { | |
180 | + return this.imageIconUrl; | |
181 | + } | |
182 | + | |
183 | + public void setImageIconUrl(String imageIconUrl) { | |
184 | + this.imageIconUrl = imageIconUrl; | |
185 | + } | |
186 | + | |
187 | + public String getImageLocal() { | |
188 | + return this.imageLocal; | |
189 | + } | |
190 | + | |
191 | + public void setImageLocal(String imageLocal) { | |
192 | + this.imageLocal = imageLocal; | |
193 | + } | |
194 | +} | ... | ... |
... | ... | @@ -0,0 +1,277 @@ |
1 | +package com.shunzhi.mychartlibrary.db; | |
2 | + | |
3 | +import android.database.Cursor; | |
4 | +import android.database.sqlite.SQLiteStatement; | |
5 | + | |
6 | +import org.greenrobot.greendao.AbstractDao; | |
7 | +import org.greenrobot.greendao.Property; | |
8 | +import org.greenrobot.greendao.internal.DaoConfig; | |
9 | +import org.greenrobot.greendao.database.Database; | |
10 | +import org.greenrobot.greendao.database.DatabaseStatement; | |
11 | + | |
12 | +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. | |
13 | +/** | |
14 | + * DAO for table "CHAT_MESSAGE_BEAN". | |
15 | +*/ | |
16 | +public class ChatMessageBeanDao1 extends AbstractDao<ChatMessageBean, Long> { | |
17 | + | |
18 | + public static final String TABLENAME = "CHAT_MESSAGE_BEAN"; | |
19 | + | |
20 | + /** | |
21 | + * Properties of entity ChatMessageBean.<br/> | |
22 | + * Can be used for QueryBuilder and for referencing column names. | |
23 | + */ | |
24 | + public static class Properties { | |
25 | + public final static Property Id = new Property(0, Long.class, "id", true, "_id"); | |
26 | + public final static Property UserId = new Property(1, String.class, "UserId", false, "UserId"); | |
27 | + public final static Property UserName = new Property(2, String.class, "UserName", false, "UserName"); | |
28 | + public final static Property UserHeadIcon = new Property(3, String.class, "UserHeadIcon", false, "UserHeadIcon"); | |
29 | + public final static Property UserContent = new Property(4, String.class, "UserContent", false, "UserContent"); | |
30 | + public final static Property Time = new Property(5, String.class, "time", false, "time"); | |
31 | + public final static Property Type = new Property(6, int.class, "type", false, "type"); | |
32 | + public final static Property Messagetype = new Property(7, int.class, "messagetype", false, "messagetype"); | |
33 | + public final static Property UserVoiceTime = new Property(8, float.class, "UserVoiceTime", false, "UserVoiceTime"); | |
34 | + public final static Property UserVoicePath = new Property(9, String.class, "UserVoicePath", false, "UserVoicePath"); | |
35 | + public final static Property UserVoiceUrl = new Property(10, String.class, "UserVoiceUrl", false, "UserVoiceUrl"); | |
36 | + public final static Property SendState = new Property(11, int.class, "sendState", false, "sendState"); | |
37 | + public final static Property ImageUrl = new Property(12, String.class, "imageUrl", false, "imageUrl"); | |
38 | + public final static Property ImageIconUrl = new Property(13, String.class, "imageIconUrl", false, "imageIconUrl"); | |
39 | + public final static Property ImageLocal = new Property(14, String.class, "imageLocal", false, "imageLocal"); | |
40 | + } | |
41 | + | |
42 | + | |
43 | + public ChatMessageBeanDao1(DaoConfig config) { | |
44 | + super(config); | |
45 | + } | |
46 | + | |
47 | + public ChatMessageBeanDao1(DaoConfig config, DaoSession daoSession) { | |
48 | + super(config, daoSession); | |
49 | + } | |
50 | + | |
51 | + /** Creates the underlying database table. */ | |
52 | + public static void createTable(Database db, boolean ifNotExists) { | |
53 | + String constraint = ifNotExists? "IF NOT EXISTS ": ""; | |
54 | + db.execSQL("CREATE TABLE " + constraint + "\"CHAT_MESSAGE_BEAN\" (" + // | |
55 | + "\"_id\" INTEGER PRIMARY KEY ," + // 0: id | |
56 | + "\"UserId\" TEXT," + // 1: UserId | |
57 | + "\"UserName\" TEXT," + // 2: UserName | |
58 | + "\"UserHeadIcon\" TEXT," + // 3: UserHeadIcon | |
59 | + "\"UserContent\" TEXT," + // 4: UserContent | |
60 | + "\"time\" TEXT," + // 5: time | |
61 | + "\"type\" INTEGER NOT NULL ," + // 6: type | |
62 | + "\"messagetype\" INTEGER NOT NULL ," + // 7: messagetype | |
63 | + "\"UserVoiceTime\" REAL NOT NULL ," + // 8: UserVoiceTime | |
64 | + "\"UserVoicePath\" TEXT," + // 9: UserVoicePath | |
65 | + "\"UserVoiceUrl\" TEXT," + // 10: UserVoiceUrl | |
66 | + "\"sendState\" INTEGER NOT NULL ," + // 11: sendState | |
67 | + "\"imageUrl\" TEXT," + // 12: imageUrl | |
68 | + "\"imageIconUrl\" TEXT," + // 13: imageIconUrl | |
69 | + "\"imageLocal\" TEXT);"); // 14: imageLocal | |
70 | + } | |
71 | + | |
72 | + /** Drops the underlying database table. */ | |
73 | + public static void dropTable(Database db, boolean ifExists) { | |
74 | + String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"CHAT_MESSAGE_BEAN\""; | |
75 | + db.execSQL(sql); | |
76 | + } | |
77 | + | |
78 | + @Override | |
79 | + protected final void bindValues(DatabaseStatement stmt, ChatMessageBean entity) { | |
80 | + stmt.clearBindings(); | |
81 | + | |
82 | + Long id = entity.getId(); | |
83 | + if (id != null) { | |
84 | + stmt.bindLong(1, id); | |
85 | + } | |
86 | + | |
87 | + String UserId = entity.getUserId(); | |
88 | + if (UserId != null) { | |
89 | + stmt.bindString(2, UserId); | |
90 | + } | |
91 | + | |
92 | + String UserName = entity.getUserName(); | |
93 | + if (UserName != null) { | |
94 | + stmt.bindString(3, UserName); | |
95 | + } | |
96 | + | |
97 | + String UserHeadIcon = entity.getUserHeadIcon(); | |
98 | + if (UserHeadIcon != null) { | |
99 | + stmt.bindString(4, UserHeadIcon); | |
100 | + } | |
101 | + | |
102 | + String UserContent = entity.getUserContent(); | |
103 | + if (UserContent != null) { | |
104 | + stmt.bindString(5, UserContent); | |
105 | + } | |
106 | + | |
107 | + String time = entity.getTime(); | |
108 | + if (time != null) { | |
109 | + stmt.bindString(6, time); | |
110 | + } | |
111 | + stmt.bindLong(7, entity.getType()); | |
112 | + stmt.bindLong(8, entity.getMessagetype()); | |
113 | + stmt.bindDouble(9, entity.getUserVoiceTime()); | |
114 | + | |
115 | + String UserVoicePath = entity.getUserVoicePath(); | |
116 | + if (UserVoicePath != null) { | |
117 | + stmt.bindString(10, UserVoicePath); | |
118 | + } | |
119 | + | |
120 | + String UserVoiceUrl = entity.getUserVoiceUrl(); | |
121 | + if (UserVoiceUrl != null) { | |
122 | + stmt.bindString(11, UserVoiceUrl); | |
123 | + } | |
124 | + stmt.bindLong(12, entity.getSendState()); | |
125 | + | |
126 | + String imageUrl = entity.getImageUrl(); | |
127 | + if (imageUrl != null) { | |
128 | + stmt.bindString(13, imageUrl); | |
129 | + } | |
130 | + | |
131 | + String imageIconUrl = entity.getImageIconUrl(); | |
132 | + if (imageIconUrl != null) { | |
133 | + stmt.bindString(14, imageIconUrl); | |
134 | + } | |
135 | + | |
136 | + String imageLocal = entity.getImageLocal(); | |
137 | + if (imageLocal != null) { | |
138 | + stmt.bindString(15, imageLocal); | |
139 | + } | |
140 | + } | |
141 | + | |
142 | + @Override | |
143 | + protected final void bindValues(SQLiteStatement stmt, ChatMessageBean entity) { | |
144 | + stmt.clearBindings(); | |
145 | + | |
146 | + Long id = entity.getId(); | |
147 | + if (id != null) { | |
148 | + stmt.bindLong(1, id); | |
149 | + } | |
150 | + | |
151 | + String UserId = entity.getUserId(); | |
152 | + if (UserId != null) { | |
153 | + stmt.bindString(2, UserId); | |
154 | + } | |
155 | + | |
156 | + String UserName = entity.getUserName(); | |
157 | + if (UserName != null) { | |
158 | + stmt.bindString(3, UserName); | |
159 | + } | |
160 | + | |
161 | + String UserHeadIcon = entity.getUserHeadIcon(); | |
162 | + if (UserHeadIcon != null) { | |
163 | + stmt.bindString(4, UserHeadIcon); | |
164 | + } | |
165 | + | |
166 | + String UserContent = entity.getUserContent(); | |
167 | + if (UserContent != null) { | |
168 | + stmt.bindString(5, UserContent); | |
169 | + } | |
170 | + | |
171 | + String time = entity.getTime(); | |
172 | + if (time != null) { | |
173 | + stmt.bindString(6, time); | |
174 | + } | |
175 | + stmt.bindLong(7, entity.getType()); | |
176 | + stmt.bindLong(8, entity.getMessagetype()); | |
177 | + stmt.bindDouble(9, entity.getUserVoiceTime()); | |
178 | + | |
179 | + String UserVoicePath = entity.getUserVoicePath(); | |
180 | + if (UserVoicePath != null) { | |
181 | + stmt.bindString(10, UserVoicePath); | |
182 | + } | |
183 | + | |
184 | + String UserVoiceUrl = entity.getUserVoiceUrl(); | |
185 | + if (UserVoiceUrl != null) { | |
186 | + stmt.bindString(11, UserVoiceUrl); | |
187 | + } | |
188 | + stmt.bindLong(12, entity.getSendState()); | |
189 | + | |
190 | + String imageUrl = entity.getImageUrl(); | |
191 | + if (imageUrl != null) { | |
192 | + stmt.bindString(13, imageUrl); | |
193 | + } | |
194 | + | |
195 | + String imageIconUrl = entity.getImageIconUrl(); | |
196 | + if (imageIconUrl != null) { | |
197 | + stmt.bindString(14, imageIconUrl); | |
198 | + } | |
199 | + | |
200 | + String imageLocal = entity.getImageLocal(); | |
201 | + if (imageLocal != null) { | |
202 | + stmt.bindString(15, imageLocal); | |
203 | + } | |
204 | + } | |
205 | + | |
206 | + @Override | |
207 | + public Long readKey(Cursor cursor, int offset) { | |
208 | + return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0); | |
209 | + } | |
210 | + | |
211 | + @Override | |
212 | + public ChatMessageBean readEntity(Cursor cursor, int offset) { | |
213 | + ChatMessageBean entity = new ChatMessageBean( // | |
214 | + cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id | |
215 | + cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1), // UserId | |
216 | + cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2), // UserName | |
217 | + cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3), // UserHeadIcon | |
218 | + cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4), // UserContent | |
219 | + cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5), // time | |
220 | + cursor.getInt(offset + 6), // type | |
221 | + cursor.getInt(offset + 7), // messagetype | |
222 | + cursor.getFloat(offset + 8), // UserVoiceTime | |
223 | + cursor.isNull(offset + 9) ? null : cursor.getString(offset + 9), // UserVoicePath | |
224 | + cursor.isNull(offset + 10) ? null : cursor.getString(offset + 10), // UserVoiceUrl | |
225 | + cursor.getInt(offset + 11), // sendState | |
226 | + cursor.isNull(offset + 12) ? null : cursor.getString(offset + 12), // imageUrl | |
227 | + cursor.isNull(offset + 13) ? null : cursor.getString(offset + 13), // imageIconUrl | |
228 | + cursor.isNull(offset + 14) ? null : cursor.getString(offset + 14) // imageLocal | |
229 | + ); | |
230 | + return entity; | |
231 | + } | |
232 | + | |
233 | + @Override | |
234 | + public void readEntity(Cursor cursor, ChatMessageBean entity, int offset) { | |
235 | + entity.setId(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0)); | |
236 | + entity.setUserId(cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1)); | |
237 | + entity.setUserName(cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2)); | |
238 | + entity.setUserHeadIcon(cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3)); | |
239 | + entity.setUserContent(cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4)); | |
240 | + entity.setTime(cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5)); | |
241 | + entity.setType(cursor.getInt(offset + 6)); | |
242 | + entity.setMessagetype(cursor.getInt(offset + 7)); | |
243 | + entity.setUserVoiceTime(cursor.getFloat(offset + 8)); | |
244 | + entity.setUserVoicePath(cursor.isNull(offset + 9) ? null : cursor.getString(offset + 9)); | |
245 | + entity.setUserVoiceUrl(cursor.isNull(offset + 10) ? null : cursor.getString(offset + 10)); | |
246 | + entity.setSendState(cursor.getInt(offset + 11)); | |
247 | + entity.setImageUrl(cursor.isNull(offset + 12) ? null : cursor.getString(offset + 12)); | |
248 | + entity.setImageIconUrl(cursor.isNull(offset + 13) ? null : cursor.getString(offset + 13)); | |
249 | + entity.setImageLocal(cursor.isNull(offset + 14) ? null : cursor.getString(offset + 14)); | |
250 | + } | |
251 | + | |
252 | + @Override | |
253 | + protected final Long updateKeyAfterInsert(ChatMessageBean entity, long rowId) { | |
254 | + entity.setId(rowId); | |
255 | + return rowId; | |
256 | + } | |
257 | + | |
258 | + @Override | |
259 | + public Long getKey(ChatMessageBean entity) { | |
260 | + if(entity != null) { | |
261 | + return entity.getId(); | |
262 | + } else { | |
263 | + return null; | |
264 | + } | |
265 | + } | |
266 | + | |
267 | + @Override | |
268 | + public boolean hasKey(ChatMessageBean entity) { | |
269 | + return entity.getId() != null; | |
270 | + } | |
271 | + | |
272 | + @Override | |
273 | + protected final boolean isEntityUpdateable() { | |
274 | + return true; | |
275 | + } | |
276 | + | |
277 | +} | ... | ... |
... | ... | @@ -0,0 +1,96 @@ |
1 | +package com.shunzhi.mychartlibrary.db; | |
2 | + | |
3 | +import android.content.Context; | |
4 | +import android.database.sqlite.SQLiteDatabase; | |
5 | +import android.database.sqlite.SQLiteDatabase.CursorFactory; | |
6 | +import android.util.Log; | |
7 | + | |
8 | +import org.greenrobot.greendao.AbstractDaoMaster; | |
9 | +import org.greenrobot.greendao.database.StandardDatabase; | |
10 | +import org.greenrobot.greendao.database.Database; | |
11 | +import org.greenrobot.greendao.database.DatabaseOpenHelper; | |
12 | +import org.greenrobot.greendao.identityscope.IdentityScopeType; | |
13 | + | |
14 | + | |
15 | +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. | |
16 | +/** | |
17 | + * Master of DAO (schema version 1): knows all DAOs. | |
18 | + */ | |
19 | +public class DaoMaster extends AbstractDaoMaster { | |
20 | + public static final int SCHEMA_VERSION = 1; | |
21 | + | |
22 | + /** Creates underlying database table using DAOs. */ | |
23 | + public static void createAllTables(Database db, boolean ifNotExists) { | |
24 | + ChatMessageBeanDao1.createTable(db, ifNotExists); | |
25 | + } | |
26 | + | |
27 | + /** Drops underlying database table using DAOs. */ | |
28 | + public static void dropAllTables(Database db, boolean ifExists) { | |
29 | + ChatMessageBeanDao1.dropTable(db, ifExists); | |
30 | + } | |
31 | + | |
32 | + /** | |
33 | + * WARNING: Drops all table on Upgrade! Use only during development. | |
34 | + * Convenience method using a {@link DevOpenHelper}. | |
35 | + */ | |
36 | + public static DaoSession newDevSession(Context context, String name) { | |
37 | + Database db = new DevOpenHelper(context, name).getWritableDb(); | |
38 | + DaoMaster daoMaster = new DaoMaster(db); | |
39 | + return daoMaster.newSession(); | |
40 | + } | |
41 | + | |
42 | + public DaoMaster(SQLiteDatabase db) { | |
43 | + this(new StandardDatabase(db)); | |
44 | + } | |
45 | + | |
46 | + public DaoMaster(Database db) { | |
47 | + super(db, SCHEMA_VERSION); | |
48 | + registerDaoClass(ChatMessageBeanDao1.class); | |
49 | + } | |
50 | + | |
51 | + public DaoSession newSession() { | |
52 | + return new DaoSession(db, IdentityScopeType.Session, daoConfigMap); | |
53 | + } | |
54 | + | |
55 | + public DaoSession newSession(IdentityScopeType type) { | |
56 | + return new DaoSession(db, type, daoConfigMap); | |
57 | + } | |
58 | + | |
59 | + /** | |
60 | + * Calls {@link #createAllTables(Database, boolean)} in {@link #onCreate(Database)} - | |
61 | + */ | |
62 | + public static abstract class OpenHelper extends DatabaseOpenHelper { | |
63 | + public OpenHelper(Context context, String name) { | |
64 | + super(context, name, SCHEMA_VERSION); | |
65 | + } | |
66 | + | |
67 | + public OpenHelper(Context context, String name, CursorFactory factory) { | |
68 | + super(context, name, factory, SCHEMA_VERSION); | |
69 | + } | |
70 | + | |
71 | + @Override | |
72 | + public void onCreate(Database db) { | |
73 | + Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION); | |
74 | + createAllTables(db, false); | |
75 | + } | |
76 | + } | |
77 | + | |
78 | + /** WARNING: Drops all table on Upgrade! Use only during development. */ | |
79 | + public static class DevOpenHelper extends OpenHelper { | |
80 | + public DevOpenHelper(Context context, String name) { | |
81 | + super(context, name); | |
82 | + } | |
83 | + | |
84 | + public DevOpenHelper(Context context, String name, CursorFactory factory) { | |
85 | + super(context, name, factory); | |
86 | + } | |
87 | + | |
88 | + @Override | |
89 | + public void onUpgrade(Database db, int oldVersion, int newVersion) { | |
90 | + Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables"); | |
91 | + dropAllTables(db, true); | |
92 | + onCreate(db); | |
93 | + } | |
94 | + } | |
95 | + | |
96 | +} | ... | ... |
... | ... | @@ -0,0 +1,45 @@ |
1 | +package com.shunzhi.mychartlibrary.db; | |
2 | + | |
3 | +import java.util.Map; | |
4 | + | |
5 | +import org.greenrobot.greendao.AbstractDao; | |
6 | +import org.greenrobot.greendao.AbstractDaoSession; | |
7 | +import org.greenrobot.greendao.database.Database; | |
8 | +import org.greenrobot.greendao.identityscope.IdentityScopeType; | |
9 | +import org.greenrobot.greendao.internal.DaoConfig; | |
10 | + | |
11 | + | |
12 | +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. | |
13 | + | |
14 | +/** | |
15 | + * {@inheritDoc} | |
16 | + * | |
17 | + * @see AbstractDaoSession | |
18 | + */ | |
19 | +public class DaoSession extends AbstractDaoSession { | |
20 | + | |
21 | + private final DaoConfig chatMessageBeanDaoConfig; | |
22 | + | |
23 | + private final ChatMessageBeanDao1 chatMessageBeanDao; | |
24 | + | |
25 | + public DaoSession(Database db, IdentityScopeType type, Map<Class<? extends AbstractDao<?, ?>>, DaoConfig> | |
26 | + daoConfigMap) { | |
27 | + super(db); | |
28 | + | |
29 | + chatMessageBeanDaoConfig = daoConfigMap.get(ChatMessageBeanDao1.class).clone(); | |
30 | + chatMessageBeanDaoConfig.initIdentityScope(type); | |
31 | + | |
32 | + chatMessageBeanDao = new ChatMessageBeanDao1(chatMessageBeanDaoConfig, this); | |
33 | + | |
34 | + registerDao(ChatMessageBean.class, chatMessageBeanDao); | |
35 | + } | |
36 | + | |
37 | + public void clear() { | |
38 | + chatMessageBeanDaoConfig.clearIdentityScope(); | |
39 | + } | |
40 | + | |
41 | + public ChatMessageBeanDao1 getChatMessageBeanDao() { | |
42 | + return chatMessageBeanDao; | |
43 | + } | |
44 | + | |
45 | +} | ... | ... |
... | ... | @@ -0,0 +1,98 @@ |
1 | +package com.shunzhi.mychartlibrary.db; | |
2 | + | |
3 | +import android.support.annotation.NonNull; | |
4 | + | |
5 | +import org.greenrobot.greendao.query.QueryBuilder; | |
6 | + | |
7 | +import java.util.List; | |
8 | + | |
9 | +/** | |
10 | + * Created by Mao Jiqing on 2016/10/15. | |
11 | + */ | |
12 | + | |
13 | +public interface IDatabase<M, K> { | |
14 | + boolean insert(M m); | |
15 | + | |
16 | + boolean delete(M m); | |
17 | + | |
18 | + boolean deleteByKey(K key); | |
19 | + | |
20 | + boolean deleteList(List<M> mList); | |
21 | + | |
22 | + boolean deleteByKeyInTx(K... key); | |
23 | + | |
24 | + boolean deleteAll(); | |
25 | + | |
26 | + boolean insertOrReplace(@NonNull M m); | |
27 | + | |
28 | + boolean update(M m); | |
29 | + | |
30 | + boolean updateInTx(M... m); | |
31 | + | |
32 | + boolean updateList(List<M> mList); | |
33 | + | |
34 | + M selectByPrimaryKey(K key); | |
35 | + | |
36 | + List<M> loadAll(); | |
37 | + | |
38 | + /** | |
39 | + * 分页加载 | |
40 | + * @param page 设定当前页数 | |
41 | + * @param number 设定一页显示数量 | |
42 | + * @return | |
43 | + */ | |
44 | + List<M> loadPages(int page, int number); | |
45 | + | |
46 | + /** | |
47 | + * 获取分页数 | |
48 | + * @param number 设定一页显示数量 | |
49 | + * @return | |
50 | + */ | |
51 | + long getPages(int number); | |
52 | + | |
53 | + boolean refresh(M m); | |
54 | + | |
55 | + /** | |
56 | + * 清理缓存 | |
57 | + */ | |
58 | + void clearDaoSession(); | |
59 | + | |
60 | + /** | |
61 | + * Delete all tables and content from our database | |
62 | + */ | |
63 | + boolean dropDatabase(); | |
64 | + | |
65 | + /** | |
66 | + * 事务 | |
67 | + */ | |
68 | + void runInTx(Runnable runnable); | |
69 | + | |
70 | + /** | |
71 | + * 添加集合 | |
72 | + * | |
73 | + * @param mList | |
74 | + */ | |
75 | + boolean insertList(List<M> mList); | |
76 | + | |
77 | + /** | |
78 | + * 添加集合 | |
79 | + * | |
80 | + * @param mList | |
81 | + */ | |
82 | + boolean insertOrReplaceList(List<M> mList); | |
83 | + | |
84 | + /** | |
85 | + * 自定义查询 | |
86 | + * | |
87 | + * @return | |
88 | + */ | |
89 | + QueryBuilder<M> getQueryBuilder(); | |
90 | + | |
91 | + /** | |
92 | + * @param where | |
93 | + * @param selectionArg | |
94 | + * @return | |
95 | + */ | |
96 | + List<M> queryRaw(String where, String... selectionArg); | |
97 | + | |
98 | +} | ... | ... |
... | ... | @@ -0,0 +1,215 @@ |
1 | +package com.shunzhi.mychartlibrary.utils; | |
2 | + | |
3 | +import android.media.MediaRecorder; | |
4 | +import android.os.Handler; | |
5 | + | |
6 | +import java.io.File; | |
7 | +import java.io.IOException; | |
8 | +import java.util.HashSet; | |
9 | +import java.util.Set; | |
10 | +import java.util.UUID; | |
11 | + | |
12 | +public class AudioManager { | |
13 | + /** | |
14 | + * 录音的时候出错 | |
15 | + */ | |
16 | + public static final int MSG_ERROR_AUDIO_RECORD = -4; | |
17 | + private MediaRecorder mRecorder; | |
18 | + private String mDirString; | |
19 | + private String mCurrentFilePathString; | |
20 | + private Handler handler; | |
21 | + private boolean isPrepared;// 是否准备好了 | |
22 | + | |
23 | + /** | |
24 | + * 单例化的方法 1 先声明一个static 类型的变量a 2 在声明默认的构造函数 3 再用public synchronized static | |
25 | + * 类名 getInstance() { if(a==null) { a=new 类();} return a; } 或者用以下的方法 | |
26 | + */ | |
27 | + | |
28 | + /** | |
29 | + * 单例化这个类 | |
30 | + */ | |
31 | + private static AudioManager mInstance; | |
32 | + | |
33 | + private AudioManager(String dir) { | |
34 | + mDirString = dir; | |
35 | + } | |
36 | + | |
37 | + public static AudioManager getInstance(String dir) { | |
38 | + if (mInstance == null) { | |
39 | + synchronized (AudioManager.class) { | |
40 | + if (mInstance == null) { | |
41 | + mInstance = new AudioManager(dir); | |
42 | + | |
43 | + } | |
44 | + } | |
45 | + } | |
46 | + return mInstance; | |
47 | + | |
48 | + } | |
49 | + | |
50 | + public void setHandle(Handler handler) { | |
51 | + this.handler = handler; | |
52 | + } | |
53 | + | |
54 | + /** | |
55 | + * 回调函数,准备完毕,准备好后,button才会开始显示录音框 | |
56 | + * | |
57 | + */ | |
58 | + public interface AudioStageListener { | |
59 | + void wellPrepared(); | |
60 | + } | |
61 | + | |
62 | + public AudioStageListener mListener; | |
63 | + | |
64 | + public void setOnAudioStageListener(AudioStageListener listener) { | |
65 | + mListener = listener; | |
66 | + } | |
67 | + | |
68 | + public void setVocDir(String dir) { | |
69 | + mDirString = dir; | |
70 | + } | |
71 | + | |
72 | + // 准备方法 | |
73 | + @SuppressWarnings("deprecation") | |
74 | + public void prepareAudio() { | |
75 | + try { | |
76 | + // 一开始应该是false的 | |
77 | + isPrepared = false; | |
78 | + | |
79 | + File dir = new File(mDirString); | |
80 | + if (!dir.exists()) { | |
81 | + dir.mkdirs(); | |
82 | + } | |
83 | + | |
84 | + String fileNameString = generalFileName(); | |
85 | + File file = new File(dir, fileNameString); | |
86 | + | |
87 | + mCurrentFilePathString = file.getAbsolutePath(); | |
88 | + | |
89 | + mRecorder = new MediaRecorder(); | |
90 | + // 设置输出文件 | |
91 | + mRecorder.setOutputFile(file.getAbsolutePath()); | |
92 | + // 设置meidaRecorder的音频源是麦克风 | |
93 | + mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); | |
94 | + // 设置文件音频的输出格式为amr | |
95 | + mRecorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR); | |
96 | + // 设置音频的编码格式为amr | |
97 | + mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); | |
98 | + | |
99 | + // 严格遵守google官方api给出的mediaRecorder的状态流程图 | |
100 | + mRecorder.prepare(); | |
101 | + | |
102 | + mRecorder.start(); | |
103 | + // 准备结束 | |
104 | + // 已经准备好了,可以录制了 | |
105 | + if (mListener != null) { | |
106 | + mListener.wellPrepared(); | |
107 | + } | |
108 | + isPrepared = true; | |
109 | + | |
110 | + } catch (IllegalStateException e) { | |
111 | + // TODO Auto-generated catch block | |
112 | + e.printStackTrace(); | |
113 | + if (handler != null) { | |
114 | + handler.sendEmptyMessage(MSG_ERROR_AUDIO_RECORD); | |
115 | + } | |
116 | + } catch (IOException e) { | |
117 | + // TODO Auto-generated catch block | |
118 | + e.printStackTrace(); | |
119 | + if (handler != null) { | |
120 | + handler.sendEmptyMessage(MSG_ERROR_AUDIO_RECORD); | |
121 | + } | |
122 | + } catch (Exception e) { | |
123 | + e.printStackTrace(); | |
124 | + if (handler != null) { | |
125 | + handler.sendEmptyMessage(MSG_ERROR_AUDIO_RECORD); | |
126 | + } | |
127 | + } | |
128 | + | |
129 | + } | |
130 | + | |
131 | + /** | |
132 | + * 随机生成文件的名称 | |
133 | + * | |
134 | + * @return | |
135 | + */ | |
136 | + private String generalFileName() { | |
137 | + // TODO Auto-generated method stub | |
138 | + | |
139 | + return UUID.randomUUID().toString() + ".amr"; | |
140 | + } | |
141 | + | |
142 | + private int vocAuthority[] = new int[10]; | |
143 | + private int vocNum = 0; | |
144 | + private boolean check = true; | |
145 | + | |
146 | + // 获得声音的level | |
147 | + public int getVoiceLevel(int maxLevel) { | |
148 | + // mRecorder.getMaxAmplitude()这个是音频的振幅范围,值域是0-32767 | |
149 | + if (isPrepared) { | |
150 | + try { | |
151 | + int vocLevel = mRecorder.getMaxAmplitude(); | |
152 | + if (check) { | |
153 | + if (vocNum >= 10) { | |
154 | + Set<Integer> set = new HashSet<Integer>(); | |
155 | + for (int i = 0; i < vocNum; i++) { | |
156 | + set.add(vocAuthority[i]); | |
157 | + } | |
158 | + if (set.size() == 1) { | |
159 | + if (handler != null) | |
160 | + handler.sendEmptyMessage(MSG_ERROR_AUDIO_RECORD); | |
161 | + vocNum = 0; | |
162 | + vocAuthority = null; | |
163 | + vocAuthority = new int[10]; | |
164 | + } else { | |
165 | + check = false; | |
166 | + } | |
167 | + } else { | |
168 | + vocAuthority[vocNum] = vocLevel; | |
169 | + vocNum++; | |
170 | + } | |
171 | + } | |
172 | + return maxLevel * vocLevel / 32768 + 1; | |
173 | + } catch (Exception e) { | |
174 | + // TODO Auto-generated catch block | |
175 | + if (handler != null) | |
176 | + handler.sendEmptyMessage(MSG_ERROR_AUDIO_RECORD); | |
177 | + } | |
178 | + } | |
179 | + | |
180 | + return 1; | |
181 | + } | |
182 | + | |
183 | + // 释放资源 | |
184 | + public void release() { | |
185 | + // 严格按照api流程进行 | |
186 | + if (null != mRecorder) { | |
187 | + isPrepared = false; | |
188 | + try { | |
189 | + mRecorder.stop(); | |
190 | + mRecorder.release(); | |
191 | + } catch (Exception e) { | |
192 | + e.printStackTrace(); | |
193 | + } | |
194 | + mRecorder = null; | |
195 | + } | |
196 | + } | |
197 | + | |
198 | + // 取消,因为prepare时产生了一个文件,所以cancel方法应该要删除这个文件, | |
199 | + // 这是与release的方法的区别 | |
200 | + public void cancel() { | |
201 | + release(); | |
202 | + if (mCurrentFilePathString != null) { | |
203 | + File file = new File(mCurrentFilePathString); | |
204 | + file.delete(); | |
205 | + mCurrentFilePathString = null; | |
206 | + } | |
207 | + | |
208 | + } | |
209 | + | |
210 | + public String getCurrentFilePath() { | |
211 | + // TODO Auto-generated method stub | |
212 | + return mCurrentFilePathString; | |
213 | + } | |
214 | + | |
215 | +} | ... | ... |
... | ... | @@ -0,0 +1,102 @@ |
1 | +package com.shunzhi.mychartlibrary.utils; | |
2 | + | |
3 | + | |
4 | + | |
5 | +import com.shunzhi.mychartlibrary.R; | |
6 | + | |
7 | +import java.util.HashMap; | |
8 | +import java.util.Map; | |
9 | + | |
10 | +public class FaceData { | |
11 | + public static Map<String, Integer> gifFaceInfo = new HashMap<String, Integer>(); | |
12 | + | |
13 | + public static final String f1 = "[:f1]"; | |
14 | + public static final String f2 = "[:f2]"; | |
15 | + public static final String f3 = "[:f3]"; | |
16 | + public static final String f4 = "[:f4]"; | |
17 | + public static final String f5 = "[:f5]"; | |
18 | + public static final String f6 = "[:f6]"; | |
19 | + public static final String f7 = "[:f7]"; | |
20 | + public static final String f8 = "[:f8]"; | |
21 | + public static final String f9 = "[:f9]"; | |
22 | + public static final String f10 = "[:f10]"; | |
23 | + public static final String f11 = "[:f11]"; | |
24 | + public static final String f12 = "[:f12]"; | |
25 | + public static final String f13 = "[:f13]"; | |
26 | + public static final String f14 = "[:f14]"; | |
27 | + public static final String f15 = "[:f15]"; | |
28 | + public static final String f16 = "[:f16]"; | |
29 | + public static final String f17 = "[:f17]"; | |
30 | + public static final String f18 = "[:f18]"; | |
31 | + public static final String f19 = "[:f19]"; | |
32 | + public static final String f20 = "[:f20]"; | |
33 | + public static final String f21 = "[:f21]"; | |
34 | + public static final String f22 = "[:f22]"; | |
35 | + public static final String f23 = "[:f23]"; | |
36 | + public static final String f24 = "[:f24]"; | |
37 | + public static final String f25 = "[:f25]"; | |
38 | + public static final String f26 = "[:f26]"; | |
39 | + public static final String f27 = "[:f27]"; | |
40 | + public static final String f28 = "[:f28]"; | |
41 | + public static final String f29 = "[:f29]"; | |
42 | + public static final String f30 = "[:f30]"; | |
43 | + public static final String f31 = "[:f31]"; | |
44 | + public static final String f32 = "[:f32]"; | |
45 | + public static final String f33 = "[:f33]"; | |
46 | + public static final String f34 = "[:f34]"; | |
47 | + public static final String f35 = "[:f35]"; | |
48 | + public static final String f36 = "[:f36]"; | |
49 | + public static final String f37 = "[:f37]"; | |
50 | + public static final String f38 = "[:f38]"; | |
51 | + public static final String f39 = "[:f39]"; | |
52 | + public static final String f40 = "[:f40]"; | |
53 | + | |
54 | + static { | |
55 | + | |
56 | + addString(gifFaceInfo, f1, R.mipmap.f1); | |
57 | + addString(gifFaceInfo, f2, R.mipmap.f2); | |
58 | + addString(gifFaceInfo, f3, R.mipmap.f3); | |
59 | + addString(gifFaceInfo, f4, R.mipmap.f4); | |
60 | + addString(gifFaceInfo, f5, R.mipmap.f5); | |
61 | + addString(gifFaceInfo, f6, R.mipmap.f6); | |
62 | + addString(gifFaceInfo, f7, R.mipmap.f7); | |
63 | + addString(gifFaceInfo, f8, R.mipmap.f8); | |
64 | + addString(gifFaceInfo, f9, R.mipmap.f9); | |
65 | + addString(gifFaceInfo, f10, R.mipmap.f10); | |
66 | + addString(gifFaceInfo, f11, R.mipmap.f11); | |
67 | + addString(gifFaceInfo, f12, R.mipmap.f12); | |
68 | + addString(gifFaceInfo, f13, R.mipmap.f13); | |
69 | + addString(gifFaceInfo, f14, R.mipmap.f14); | |
70 | + addString(gifFaceInfo, f15, R.mipmap.f15); | |
71 | + addString(gifFaceInfo, f16, R.mipmap.f16); | |
72 | + addString(gifFaceInfo, f17, R.mipmap.f17); | |
73 | + addString(gifFaceInfo, f18, R.mipmap.f18); | |
74 | + addString(gifFaceInfo, f19, R.mipmap.f19); | |
75 | + addString(gifFaceInfo, f20, R.mipmap.f20); | |
76 | + addString(gifFaceInfo, f21, R.mipmap.f21); | |
77 | + addString(gifFaceInfo, f22, R.mipmap.f22); | |
78 | + addString(gifFaceInfo, f23, R.mipmap.f23); | |
79 | + addString(gifFaceInfo, f24, R.mipmap.f24); | |
80 | + addString(gifFaceInfo, f25, R.mipmap.f25); | |
81 | + addString(gifFaceInfo, f26, R.mipmap.f26); | |
82 | + addString(gifFaceInfo, f27, R.mipmap.f27); | |
83 | + addString(gifFaceInfo, f28, R.mipmap.f28); | |
84 | + addString(gifFaceInfo, f29, R.mipmap.f29); | |
85 | + addString(gifFaceInfo, f30, R.mipmap.f30); | |
86 | + addString(gifFaceInfo, f31, R.mipmap.f31); | |
87 | + addString(gifFaceInfo, f32, R.mipmap.f32); | |
88 | + addString(gifFaceInfo, f33, R.mipmap.f33); | |
89 | + addString(gifFaceInfo, f34, R.mipmap.f34); | |
90 | + addString(gifFaceInfo, f35, R.mipmap.f35); | |
91 | + addString(gifFaceInfo, f36, R.mipmap.f36); | |
92 | + addString(gifFaceInfo, f37, R.mipmap.f37); | |
93 | + addString(gifFaceInfo, f38, R.mipmap.f38); | |
94 | + addString(gifFaceInfo, f39, R.mipmap.f39); | |
95 | + addString(gifFaceInfo, f40, R.mipmap.f40); | |
96 | + } | |
97 | + | |
98 | + private static void addString(Map<String, Integer> map, String smile, | |
99 | + int resource) { | |
100 | + map.put(smile, resource); | |
101 | + } | |
102 | +} | |
0 | 103 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,372 @@ |
1 | +package com.shunzhi.mychartlibrary.utils; | |
2 | + | |
3 | +import android.annotation.SuppressLint; | |
4 | +import android.annotation.TargetApi; | |
5 | +import android.content.ContentUris; | |
6 | +import android.content.Context; | |
7 | +import android.database.Cursor; | |
8 | +import android.graphics.Bitmap; | |
9 | +import android.net.Uri; | |
10 | +import android.os.Build; | |
11 | +import android.os.Environment; | |
12 | +import android.provider.DocumentsContract; | |
13 | +import android.provider.MediaStore; | |
14 | +import android.util.Base64; | |
15 | + | |
16 | +import java.io.BufferedReader; | |
17 | +import java.io.ByteArrayOutputStream; | |
18 | +import java.io.File; | |
19 | +import java.io.FileInputStream; | |
20 | +import java.io.FileNotFoundException; | |
21 | +import java.io.FileOutputStream; | |
22 | +import java.io.IOException; | |
23 | +import java.io.InputStream; | |
24 | +import java.io.InputStreamReader; | |
25 | +import java.util.ArrayList; | |
26 | +import java.util.List; | |
27 | + | |
28 | +public class FileSaveUtil { | |
29 | + public static final String SD_CARD_PATH = Environment.getExternalStorageDirectory().toString() + "/MAXI/"; | |
30 | + | |
31 | + // public static final String saveFn = SD_CARD_PATH | |
32 | +// + "/user_chat_data/"; | |
33 | +// public static final String savelistFn = SD_CARD_PATH | |
34 | +// + "/user_chat_data/chatList/"; | |
35 | +// public static final String savechannelFn = SD_CARD_PATH | |
36 | +// + "/user_chat_data/channel_id/"; | |
37 | +// public static final String saveUnReadFn = SD_CARD_PATH | |
38 | +// + "/user_chat_data/UnRead/"; | |
39 | + public static final String voice_dir = SD_CARD_PATH | |
40 | + + "/voice_data/"; | |
41 | + | |
42 | + /** | |
43 | + * SD卡是否存在 | |
44 | + **/ | |
45 | + private boolean hasSD = false; | |
46 | + /** | |
47 | + * 当前程序包的路径 | |
48 | + **/ | |
49 | + private String FILESPATH; | |
50 | + | |
51 | + public static boolean isFileExists(File file) { | |
52 | + if (!file.exists()) { | |
53 | + return false; | |
54 | + } | |
55 | + return true; | |
56 | + } | |
57 | + | |
58 | + /** | |
59 | + * 获取文件夹下的所有文件名 | |
60 | + */ | |
61 | + public static List<String> getFileName(String fileName) { | |
62 | + List<String> fileList = new ArrayList<String>(); | |
63 | + String path = fileName; // 路径 | |
64 | + File f = new File(path); | |
65 | + if (!f.exists()) { | |
66 | + System.out.println(path + " not exists"); | |
67 | + return null; | |
68 | + } | |
69 | + | |
70 | + File fa[] = f.listFiles(); | |
71 | + for (int i = 0; i < fa.length; i++) { | |
72 | + File fs = fa[i]; | |
73 | + if (!fs.isDirectory()) { | |
74 | + fileList.add(fs.getName()); | |
75 | + } | |
76 | + } | |
77 | + return fileList; | |
78 | + } | |
79 | + | |
80 | + /** | |
81 | + * 在SD卡上创建文件 | |
82 | + * | |
83 | + * @throws IOException | |
84 | + */ | |
85 | + public static File createSDFile(String fileName) throws IOException { | |
86 | + File file = new File(fileName); | |
87 | + if (!isFileExists(file)) | |
88 | + if (file.isDirectory()) { | |
89 | + file.mkdirs(); | |
90 | + } else { | |
91 | + file.createNewFile(); | |
92 | + } | |
93 | + return file; | |
94 | + } | |
95 | + | |
96 | + /** | |
97 | + * 在SD卡上创建文件夹 | |
98 | + * | |
99 | + * @throws IOException | |
100 | + */ | |
101 | + public static File createSDDirectory(String fileName) throws IOException { | |
102 | + File file = new File(fileName); | |
103 | + if (!isFileExists(file)) | |
104 | + file.mkdirs(); | |
105 | + return file; | |
106 | + } | |
107 | + | |
108 | +// /** | |
109 | +// * @content 存储内容 | |
110 | +// * @file 文件目录 | |
111 | +// * @isAppend 是否追加 | |
112 | +// */ | |
113 | +// public synchronized static void writeString(String content, String file, boolean isAppend) { | |
114 | +// try { | |
115 | +// createSDDirectory(saveFn); | |
116 | +// createSDDirectory(savelistFn); | |
117 | +// createSDDirectory(savechannelFn); | |
118 | +// byte[] data = content.getBytes("utf-8"); | |
119 | +// writeBytes(file, data, isAppend); | |
120 | +// } catch (Exception e) { | |
121 | +// System.out.println(e.getMessage()); | |
122 | +// } | |
123 | +// | |
124 | +// } | |
125 | + | |
126 | + public synchronized static boolean writeBytes(String filePath, byte[] data, | |
127 | + boolean isAppend) { | |
128 | + try { | |
129 | + FileOutputStream fos; | |
130 | + if (isAppend) | |
131 | + fos = new FileOutputStream(filePath, true); | |
132 | + else | |
133 | + fos = new FileOutputStream(filePath); | |
134 | + fos.write(data); | |
135 | + fos.close(); | |
136 | + return true; | |
137 | + } catch (Exception e) { | |
138 | + System.out.println(e.getMessage()); | |
139 | + } | |
140 | + return false; | |
141 | + } | |
142 | + | |
143 | + /** | |
144 | + * 读取SD卡中文本文件 | |
145 | + * | |
146 | + * @param fileName | |
147 | + * @return | |
148 | + */ | |
149 | + public synchronized static String readSDFile(String fileName) { | |
150 | + StringBuffer sb = new StringBuffer(); | |
151 | + File f1 = new File(fileName); | |
152 | + String str = null; | |
153 | + try { | |
154 | + InputStream is = new FileInputStream(f1); | |
155 | + InputStreamReader input = new InputStreamReader(is, "UTF-8"); | |
156 | + @SuppressWarnings("resource") | |
157 | + BufferedReader reader = new BufferedReader(input); | |
158 | + while ((str = reader.readLine()) != null) { | |
159 | + sb.append(str); | |
160 | + } | |
161 | + } catch (FileNotFoundException e) { | |
162 | + // TODO Auto-generated catch block | |
163 | + e.printStackTrace(); | |
164 | + } catch (IOException e) { | |
165 | + // TODO Auto-generated catch block | |
166 | + e.printStackTrace(); | |
167 | + } | |
168 | + return sb.toString(); | |
169 | + } | |
170 | + | |
171 | + public String getFILESPATH() { | |
172 | + return FILESPATH; | |
173 | + } | |
174 | + | |
175 | + public boolean hasSD() { | |
176 | + return hasSD; | |
177 | + } | |
178 | + | |
179 | + /** | |
180 | + * 删除单个文件 | |
181 | + * | |
182 | + * @param filePath 被删除文件的文件名 | |
183 | + * @return 文件删除成功返回true,否则返回false | |
184 | + */ | |
185 | + public static boolean deleteFile(String filePath) { | |
186 | + File file = new File(filePath); | |
187 | + if (file.isFile() && file.exists()) { | |
188 | + return file.delete(); | |
189 | + } | |
190 | + return false; | |
191 | + } | |
192 | + | |
193 | + /** | |
194 | + * 删除文件夹以及目录下的文件 | |
195 | + * | |
196 | + * @param filePath 被删除目录的文件路径 | |
197 | + * @return 目录删除成功返回true,否则返回false | |
198 | + */ | |
199 | + public static boolean deleteDirectory(String filePath) { | |
200 | + boolean flag = false; | |
201 | + // 如果filePath不以文件分隔符结尾,自动添加文件分隔符 | |
202 | + if (!filePath.endsWith(File.separator)) { | |
203 | + filePath = filePath + File.separator; | |
204 | + } | |
205 | + File dirFile = new File(filePath); | |
206 | + if (!dirFile.exists() || !dirFile.isDirectory()) { | |
207 | + return false; | |
208 | + } | |
209 | + flag = true; | |
210 | + File[] files = dirFile.listFiles(); | |
211 | + // 遍历删除文件夹下的所有文件(包括子目录) | |
212 | + for (int i = 0; i < files.length; i++) { | |
213 | + if (files[i].isFile()) { | |
214 | + // 删除子文件 | |
215 | + flag = deleteFile(files[i].getAbsolutePath()); | |
216 | + if (!flag) | |
217 | + break; | |
218 | + } else { | |
219 | + // 删除子目录 | |
220 | + flag = deleteDirectory(files[i].getAbsolutePath()); | |
221 | + if (!flag) | |
222 | + break; | |
223 | + } | |
224 | + } | |
225 | + if (!flag) | |
226 | + return false; | |
227 | + // 删除当前空目录 | |
228 | + return dirFile.delete(); | |
229 | + } | |
230 | + | |
231 | + public static boolean saveBitmap(Bitmap bm, String picName) { | |
232 | + try { | |
233 | + File f = new File(picName); | |
234 | + if (f.exists()) { | |
235 | + f.delete(); | |
236 | + } | |
237 | + FileOutputStream out = new FileOutputStream(f); | |
238 | + bm.compress(Bitmap.CompressFormat.PNG, 100, out); | |
239 | + out.flush(); | |
240 | + out.close(); | |
241 | + return true; | |
242 | + } catch (FileNotFoundException e) { | |
243 | + e.printStackTrace(); | |
244 | + return false; | |
245 | + } catch (IOException e) { | |
246 | + e.printStackTrace(); | |
247 | + return false; | |
248 | + } | |
249 | + } | |
250 | + | |
251 | + /** | |
252 | + * 把文件转换成base64 | |
253 | + * | |
254 | + * @param path | |
255 | + * @return | |
256 | + */ | |
257 | + public static String encodeBase64File(String path) throws Exception { | |
258 | + byte[] videoBytes; | |
259 | + ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |
260 | + @SuppressWarnings("resource") | |
261 | + FileInputStream fis = new FileInputStream(new File(path)); | |
262 | + byte[] buf = new byte[1024]; | |
263 | + int n; | |
264 | + while (-1 != (n = fis.read(buf))) | |
265 | + baos.write(buf, 0, n); | |
266 | + videoBytes = baos.toByteArray(); | |
267 | + return Base64.encodeToString(videoBytes, Base64.NO_WRAP); | |
268 | + } | |
269 | + | |
270 | + /** | |
271 | + * 根据相册媒体库路径转换成sd卡路径 | |
272 | + * | |
273 | + * @param context | |
274 | + * @param uri | |
275 | + * @return | |
276 | + */ | |
277 | + @TargetApi(Build.VERSION_CODES.KITKAT) | |
278 | + public static String getPath(final Context context, final Uri uri) { | |
279 | + final boolean isOverKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; | |
280 | + // DocumentProvider | |
281 | + if (isOverKitKat && DocumentsContract.isDocumentUri(context, uri)) { | |
282 | + // ExternalStorageProvider | |
283 | + if (isExternalStorageDocument(uri)) { | |
284 | + final String docId = DocumentsContract.getDocumentId(uri); | |
285 | + final String[] split = docId.split(":"); | |
286 | + final String type = split[0]; | |
287 | + if ("primary".equalsIgnoreCase(type)) { | |
288 | + return Environment.getExternalStorageDirectory() + "/" | |
289 | + + split[1]; | |
290 | + } | |
291 | + } | |
292 | + // DownloadsProvider | |
293 | + else if (isDownloadsDocument(uri)) { | |
294 | + final String id = DocumentsContract.getDocumentId(uri); | |
295 | + final Uri contentUri = ContentUris.withAppendedId( | |
296 | + Uri.parse("content://downloads/public_downloads"), | |
297 | + Long.valueOf(id)); | |
298 | + return getDataColumn(context, contentUri, null, null); | |
299 | + } | |
300 | + // MediaProvider | |
301 | + else if (isMediaDocument(uri)) { | |
302 | + final String docId = DocumentsContract.getDocumentId(uri); | |
303 | + final String[] split = docId.split(":"); | |
304 | + final String type = split[0]; | |
305 | + Uri contentUri = null; | |
306 | + if ("image".equals(type)) { | |
307 | + contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; | |
308 | + } else if ("video".equals(type)) { | |
309 | + contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; | |
310 | + } else if ("audio".equals(type)) { | |
311 | + contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; | |
312 | + } | |
313 | + final String selection = "_id=?"; | |
314 | + final String[] selectionArgs = new String[]{split[1]}; | |
315 | + return getDataColumn(context, contentUri, selection, | |
316 | + selectionArgs); | |
317 | + } | |
318 | + } | |
319 | + // MediaStore (and general) | |
320 | + else if ("content".equalsIgnoreCase(uri.getScheme())) { | |
321 | + // Return the remote address | |
322 | + if (isGooglePhotosUri(uri)) | |
323 | + return uri.getLastPathSegment(); | |
324 | + return getDataColumn(context, uri, null, null); | |
325 | + } | |
326 | + // File | |
327 | + else if ("file".equalsIgnoreCase(uri.getScheme())) { | |
328 | + return uri.getPath(); | |
329 | + } | |
330 | + return null; | |
331 | + } | |
332 | + | |
333 | + @SuppressLint("NewApi") | |
334 | + public static String getDataColumn(Context context, Uri uri, | |
335 | + String selection, String[] selectionArgs) { | |
336 | + Cursor cursor = null; | |
337 | + final String column = "_data"; | |
338 | + final String[] projection = {column}; | |
339 | + try { | |
340 | + cursor = context.getContentResolver().query(uri, projection, | |
341 | + selection, selectionArgs, null); | |
342 | + if (cursor != null && cursor.moveToFirst()) { | |
343 | + final int index = cursor.getColumnIndexOrThrow(column); | |
344 | + return cursor.getString(index); | |
345 | + } | |
346 | + } finally { | |
347 | + if (cursor != null) | |
348 | + cursor.close(); | |
349 | + } | |
350 | + return null; | |
351 | + } | |
352 | + | |
353 | + public static boolean isGooglePhotosUri(Uri uri) { | |
354 | + return "com.google.android.apps.photos.content".equals(uri | |
355 | + .getAuthority()); | |
356 | + } | |
357 | + | |
358 | + public static boolean isDownloadsDocument(Uri uri) { | |
359 | + return "com.android.providers.downloads.documents".equals(uri | |
360 | + .getAuthority()); | |
361 | + } | |
362 | + | |
363 | + public static boolean isMediaDocument(Uri uri) { | |
364 | + return "com.android.providers.media.documents".equals(uri | |
365 | + .getAuthority()); | |
366 | + } | |
367 | + | |
368 | + public static boolean isExternalStorageDocument(Uri uri) { | |
369 | + return "com.android.externalstorage.documents".equals(uri | |
370 | + .getAuthority()); | |
371 | + } | |
372 | +} | |
0 | 373 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,625 @@ |
1 | +package com.shunzhi.mychartlibrary.utils; | |
2 | + | |
3 | +import android.graphics.Bitmap; | |
4 | +import android.graphics.Bitmap.Config; | |
5 | + | |
6 | +import java.io.InputStream; | |
7 | +import java.util.Vector; | |
8 | + | |
9 | +//Handler for read & extract Bitmap from *.gif | |
10 | +public class GifOpenHelper { | |
11 | + | |
12 | + // to store *.gif data, Bitmap & delay | |
13 | + class GifFrame { | |
14 | + // to access image & delay w/o interface | |
15 | + public Bitmap image; | |
16 | + public int delay; | |
17 | + | |
18 | + public GifFrame(Bitmap im, int del) { | |
19 | + image = im; | |
20 | + delay = del; | |
21 | + } | |
22 | + | |
23 | + } | |
24 | + | |
25 | + // to define some error type | |
26 | + public static final int STATUS_OK = 0; | |
27 | + public static final int STATUS_FORMAT_ERROR = 1; | |
28 | + public static final int STATUS_OPEN_ERROR = 2; | |
29 | + | |
30 | + protected int status; | |
31 | + | |
32 | + protected InputStream in; | |
33 | + | |
34 | + protected int width; // full image width | |
35 | + protected int height; // full image height | |
36 | + protected boolean gctFlag; // global color table used | |
37 | + protected int gctSize; // size of global color table | |
38 | + protected int loopCount = 1; // iterations; 0 = repeat forever | |
39 | + | |
40 | + protected int[] gct; // global color table | |
41 | + protected int[] lct; // local color table | |
42 | + protected int[] act; // active color table | |
43 | + | |
44 | + protected int bgIndex; // background color index | |
45 | + protected int bgColor; // background color | |
46 | + protected int lastBgColor; // previous bg color | |
47 | + protected int pixelAspect; // pixel aspect ratio | |
48 | + | |
49 | + protected boolean lctFlag; // local color table flag | |
50 | + protected boolean interlace; // interlace flag | |
51 | + protected int lctSize; // local color table size | |
52 | + | |
53 | + protected int ix, iy, iw, ih; // current image rectangle | |
54 | + protected int lrx, lry, lrw, lrh; | |
55 | + protected Bitmap image; // current frame | |
56 | + protected Bitmap lastImage; // previous frame | |
57 | + protected int frameindex = 0; | |
58 | + | |
59 | + public int getFrameindex() { | |
60 | + return frameindex; | |
61 | + } | |
62 | + | |
63 | + public void setFrameindex(int frameindex) { | |
64 | + this.frameindex = frameindex; | |
65 | + if (frameindex > frames.size() - 1) { | |
66 | + frameindex = 0; | |
67 | + } | |
68 | + } | |
69 | + | |
70 | + protected byte[] block = new byte[256]; // current data block | |
71 | + protected int blockSize = 0; // block size | |
72 | + | |
73 | + // last graphic control extension info | |
74 | + protected int dispose = 0; | |
75 | + // 0=no action; 1=leave in place; 2=restore to bg; 3=restore to prev | |
76 | + protected int lastDispose = 0; | |
77 | + protected boolean transparency = false; // use transparent color | |
78 | + protected int delay = 0; // delay in milliseconds | |
79 | + protected int transIndex; // transparent color index | |
80 | + | |
81 | + protected static final int MaxStackSize = 4096; | |
82 | + // max decoder pixel stack size | |
83 | + | |
84 | + // LZW decoder working arrays | |
85 | + protected short[] prefix; | |
86 | + protected byte[] suffix; | |
87 | + protected byte[] pixelStack; | |
88 | + protected byte[] pixels; | |
89 | + | |
90 | + protected Vector<GifFrame> frames; // frames read from current file | |
91 | + protected int frameCount; | |
92 | + | |
93 | + // to get its Width / Height | |
94 | + public int getWidth() { | |
95 | + return width; | |
96 | + } | |
97 | + | |
98 | + public int getHeigh() { | |
99 | + return height; | |
100 | + } | |
101 | + | |
102 | + /** | |
103 | + * Gets display duration for specified frame. | |
104 | + * | |
105 | + * @param n | |
106 | + * int index of frame | |
107 | + * @return delay in milliseconds | |
108 | + */ | |
109 | + public int getDelay(int n) { | |
110 | + delay = -1; | |
111 | + if ((n >= 0) && (n < frameCount)) { | |
112 | + delay = ((GifFrame) frames.elementAt(n)).delay; | |
113 | + } | |
114 | + return delay; | |
115 | + } | |
116 | + | |
117 | + public int getFrameCount() { | |
118 | + return frameCount; | |
119 | + } | |
120 | + | |
121 | + public Bitmap getImage() { | |
122 | + return getFrame(0); | |
123 | + } | |
124 | + | |
125 | + public int getLoopCount() { | |
126 | + return loopCount; | |
127 | + } | |
128 | + | |
129 | + protected void setPixels() { | |
130 | + int[] dest = new int[width * height]; | |
131 | + // fill in starting image contents based on last image's dispose code | |
132 | + if (lastDispose > 0) { | |
133 | + if (lastDispose == 3) { | |
134 | + // use image before last | |
135 | + int n = frameCount - 2; | |
136 | + if (n > 0) { | |
137 | + lastImage = getFrame(n - 1); | |
138 | + } else { | |
139 | + lastImage = null; | |
140 | + } | |
141 | + } | |
142 | + if (lastImage != null) { | |
143 | + lastImage.getPixels(dest, 0, width, 0, 0, width, height); | |
144 | + // copy pixels | |
145 | + if (lastDispose == 2) { | |
146 | + // fill last image rect area with background color | |
147 | + int c = 0; | |
148 | + if (!transparency) { | |
149 | + c = lastBgColor; | |
150 | + } | |
151 | + for (int i = 0; i < lrh; i++) { | |
152 | + int n1 = (lry + i) * width + lrx; | |
153 | + int n2 = n1 + lrw; | |
154 | + for (int k = n1; k < n2; k++) { | |
155 | + dest[k] = c; | |
156 | + } | |
157 | + } | |
158 | + } | |
159 | + } | |
160 | + } | |
161 | + | |
162 | + // copy each source line to the appropriate place in the destination | |
163 | + int pass = 1; | |
164 | + int inc = 8; | |
165 | + int iline = 0; | |
166 | + for (int i = 0; i < ih; i++) { | |
167 | + int line = i; | |
168 | + if (interlace) { | |
169 | + if (iline >= ih) { | |
170 | + pass++; | |
171 | + switch (pass) { | |
172 | + case 2: | |
173 | + iline = 4; | |
174 | + break; | |
175 | + case 3: | |
176 | + iline = 2; | |
177 | + inc = 4; | |
178 | + break; | |
179 | + case 4: | |
180 | + iline = 1; | |
181 | + inc = 2; | |
182 | + } | |
183 | + } | |
184 | + line = iline; | |
185 | + iline += inc; | |
186 | + } | |
187 | + line += iy; | |
188 | + if (line < height) { | |
189 | + int k = line * width; | |
190 | + int dx = k + ix; // start of line in dest | |
191 | + int dlim = dx + iw; // end of dest line | |
192 | + if ((k + width) < dlim) { | |
193 | + dlim = k + width; // past dest edge | |
194 | + } | |
195 | + int sx = i * iw; // start of line in source | |
196 | + while (dx < dlim) { | |
197 | + // map color and insert in destination | |
198 | + int index = ((int) pixels[sx++]) & 0xff; | |
199 | + int c = act[index]; | |
200 | + if (c != 0) { | |
201 | + dest[dx] = c; | |
202 | + } | |
203 | + dx++; | |
204 | + } | |
205 | + } | |
206 | + } | |
207 | + image = Bitmap.createBitmap(dest, width, height, Config.ARGB_4444); | |
208 | + } | |
209 | + | |
210 | + public Bitmap getFrame(int n) { | |
211 | + Bitmap im = null; | |
212 | + if ((n >= 0) && (n < frameCount)) { | |
213 | + im = ((GifFrame) frames.elementAt(n)).image; | |
214 | + } | |
215 | + return im; | |
216 | + } | |
217 | + | |
218 | + public Bitmap nextBitmap() { | |
219 | + frameindex++; | |
220 | + if (frameindex > frames.size() - 1) { | |
221 | + frameindex = 0; | |
222 | + } | |
223 | + return ((GifFrame) frames.elementAt(frameindex)).image; | |
224 | + } | |
225 | + | |
226 | + public int nextDelay() { | |
227 | + return ((GifFrame) frames.elementAt(frameindex)).delay; | |
228 | + } | |
229 | + | |
230 | + // to read & parse all *.gif stream | |
231 | + public int read(InputStream is) { | |
232 | + init(); | |
233 | + if (is != null) { | |
234 | + in = is; | |
235 | + | |
236 | + readHeader(); | |
237 | + if (!err()) { | |
238 | + readContents(); | |
239 | + if (frameCount < 0) { | |
240 | + status = STATUS_FORMAT_ERROR; | |
241 | + } | |
242 | + } | |
243 | + } else { | |
244 | + status = STATUS_OPEN_ERROR; | |
245 | + } | |
246 | + try { | |
247 | + is.close(); | |
248 | + } catch (Exception e) { | |
249 | + e.printStackTrace(); | |
250 | + } | |
251 | + return status; | |
252 | + } | |
253 | + | |
254 | + protected void decodeImageData() { | |
255 | + int NullCode = -1; | |
256 | + int npix = iw * ih; | |
257 | + int available, clear, code_mask, code_size, end_of_information, in_code, old_code, bits, code, count, i, datum, data_size, first, top, bi, pi; | |
258 | + | |
259 | + if ((pixels == null) || (pixels.length < npix)) { | |
260 | + pixels = new byte[npix]; // allocate new pixel array | |
261 | + } | |
262 | + if (prefix == null) { | |
263 | + prefix = new short[MaxStackSize]; | |
264 | + } | |
265 | + if (suffix == null) { | |
266 | + suffix = new byte[MaxStackSize]; | |
267 | + } | |
268 | + if (pixelStack == null) { | |
269 | + pixelStack = new byte[MaxStackSize + 1]; | |
270 | + } | |
271 | + // Initialize GIF data stream decoder. | |
272 | + data_size = read(); | |
273 | + clear = 1 << data_size; | |
274 | + end_of_information = clear + 1; | |
275 | + available = clear + 2; | |
276 | + old_code = NullCode; | |
277 | + code_size = data_size + 1; | |
278 | + code_mask = (1 << code_size) - 1; | |
279 | + for (code = 0; code < clear; code++) { | |
280 | + prefix[code] = 0; | |
281 | + suffix[code] = (byte) code; | |
282 | + } | |
283 | + | |
284 | + // Decode GIF pixel stream. | |
285 | + datum = bits = count = first = top = pi = bi = 0; | |
286 | + for (i = 0; i < npix;) { | |
287 | + if (top == 0) { | |
288 | + if (bits < code_size) { | |
289 | + // Load bytes until there are enough bits for a code. | |
290 | + if (count == 0) { | |
291 | + // Read a new data block. | |
292 | + count = readBlock(); | |
293 | + if (count <= 0) { | |
294 | + break; | |
295 | + } | |
296 | + bi = 0; | |
297 | + } | |
298 | + datum += (((int) block[bi]) & 0xff) << bits; | |
299 | + bits += 8; | |
300 | + bi++; | |
301 | + count--; | |
302 | + continue; | |
303 | + } | |
304 | + // Get the next code. | |
305 | + code = datum & code_mask; | |
306 | + datum >>= code_size; | |
307 | + bits -= code_size; | |
308 | + | |
309 | + // Interpret the code | |
310 | + if ((code > available) || (code == end_of_information)) { | |
311 | + break; | |
312 | + } | |
313 | + if (code == clear) { | |
314 | + // Reset decoder. | |
315 | + code_size = data_size + 1; | |
316 | + code_mask = (1 << code_size) - 1; | |
317 | + available = clear + 2; | |
318 | + old_code = NullCode; | |
319 | + continue; | |
320 | + } | |
321 | + if (old_code == NullCode) { | |
322 | + pixelStack[top++] = suffix[code]; | |
323 | + old_code = code; | |
324 | + first = code; | |
325 | + continue; | |
326 | + } | |
327 | + in_code = code; | |
328 | + if (code == available) { | |
329 | + pixelStack[top++] = (byte) first; | |
330 | + code = old_code; | |
331 | + } | |
332 | + while (code > clear) { | |
333 | + pixelStack[top++] = suffix[code]; | |
334 | + code = prefix[code]; | |
335 | + } | |
336 | + first = ((int) suffix[code]) & 0xff; | |
337 | + // Add a new string to the string table, | |
338 | + if (available >= MaxStackSize) { | |
339 | + break; | |
340 | + } | |
341 | + pixelStack[top++] = (byte) first; | |
342 | + prefix[available] = (short) old_code; | |
343 | + suffix[available] = (byte) first; | |
344 | + available++; | |
345 | + if (((available & code_mask) == 0) | |
346 | + && (available < MaxStackSize)) { | |
347 | + code_size++; | |
348 | + code_mask += available; | |
349 | + } | |
350 | + old_code = in_code; | |
351 | + } | |
352 | + | |
353 | + // Pop a pixel off the pixel stack. | |
354 | + top--; | |
355 | + pixels[pi++] = pixelStack[top]; | |
356 | + i++; | |
357 | + } | |
358 | + for (i = pi; i < npix; i++) { | |
359 | + pixels[i] = 0; // clear missing pixels | |
360 | + } | |
361 | + } | |
362 | + | |
363 | + protected boolean err() { | |
364 | + return status != STATUS_OK; | |
365 | + } | |
366 | + | |
367 | + // to initia variable | |
368 | + public void init() { | |
369 | + status = STATUS_OK; | |
370 | + frameCount = 0; | |
371 | + frames = new Vector<GifFrame>(); | |
372 | + gct = null; | |
373 | + lct = null; | |
374 | + } | |
375 | + | |
376 | + protected int read() { | |
377 | + int curByte = 0; | |
378 | + try { | |
379 | + curByte = in.read(); | |
380 | + } catch (Exception e) { | |
381 | + status = STATUS_FORMAT_ERROR; | |
382 | + } | |
383 | + return curByte; | |
384 | + } | |
385 | + | |
386 | + protected int readBlock() { | |
387 | + blockSize = read(); | |
388 | + int n = 0; | |
389 | + if (blockSize > 0) { | |
390 | + try { | |
391 | + int count = 0; | |
392 | + while (n < blockSize) { | |
393 | + count = in.read(block, n, blockSize - n); | |
394 | + if (count == -1) { | |
395 | + break; | |
396 | + } | |
397 | + n += count; | |
398 | + } | |
399 | + } catch (Exception e) { | |
400 | + e.printStackTrace(); | |
401 | + } | |
402 | + if (n < blockSize) { | |
403 | + status = STATUS_FORMAT_ERROR; | |
404 | + } | |
405 | + } | |
406 | + return n; | |
407 | + } | |
408 | + | |
409 | + // Global Color Table | |
410 | + protected int[] readColorTable(int ncolors) { | |
411 | + int nbytes = 3 * ncolors; | |
412 | + int[] tab = null; | |
413 | + byte[] c = new byte[nbytes]; | |
414 | + int n = 0; | |
415 | + try { | |
416 | + n = in.read(c); | |
417 | + } catch (Exception e) { | |
418 | + e.printStackTrace(); | |
419 | + } | |
420 | + if (n < nbytes) { | |
421 | + status = STATUS_FORMAT_ERROR; | |
422 | + } else { | |
423 | + tab = new int[256]; // max size to avoid bounds checks | |
424 | + int i = 0; | |
425 | + int j = 0; | |
426 | + while (i < ncolors) { | |
427 | + int r = ((int) c[j++]) & 0xff; | |
428 | + int g = ((int) c[j++]) & 0xff; | |
429 | + int b = ((int) c[j++]) & 0xff; | |
430 | + tab[i++] = 0xff000000 | (r << 16) | (g << 8) | b; | |
431 | + } | |
432 | + } | |
433 | + return tab; | |
434 | + } | |
435 | + | |
436 | + // Image Descriptor | |
437 | + protected void readContents() { | |
438 | + // read GIF file content blocks | |
439 | + boolean done = false; | |
440 | + while (!(done || err())) { | |
441 | + int code = read(); | |
442 | + switch (code) { | |
443 | + case 0x2C: // image separator | |
444 | + readImage(); | |
445 | + break; | |
446 | + case 0x21: // extension | |
447 | + code = read(); | |
448 | + switch (code) { | |
449 | + case 0xf9: // graphics control extension | |
450 | + readGraphicControlExt(); | |
451 | + break; | |
452 | + | |
453 | + case 0xff: // application extension | |
454 | + readBlock(); | |
455 | + String app = ""; | |
456 | + for (int i = 0; i < 11; i++) { | |
457 | + app += (char) block[i]; | |
458 | + } | |
459 | + if (app.equals("NETSCAPE2.0")) { | |
460 | + readNetscapeExt(); | |
461 | + } else { | |
462 | + skip(); // don't care | |
463 | + } | |
464 | + break; | |
465 | + default: // uninteresting extension | |
466 | + skip(); | |
467 | + } | |
468 | + break; | |
469 | + | |
470 | + case 0x3b: // terminator | |
471 | + done = true; | |
472 | + break; | |
473 | + | |
474 | + case 0x00: // bad byte, but keep going and see what happens | |
475 | + break; | |
476 | + default: | |
477 | + status = STATUS_FORMAT_ERROR; | |
478 | + } | |
479 | + } | |
480 | + } | |
481 | + | |
482 | + protected void readGraphicControlExt() { | |
483 | + read(); // block size | |
484 | + int packed = read(); // packed fields | |
485 | + dispose = (packed & 0x1c) >> 2; // disposal method | |
486 | + if (dispose == 0) { | |
487 | + dispose = 1; // elect to keep old image if discretionary | |
488 | + } | |
489 | + transparency = (packed & 1) != 0; | |
490 | + delay = readShort() * 10; // delay in milliseconds | |
491 | + transIndex = read(); // transparent color index | |
492 | + read(); // block terminator | |
493 | + } | |
494 | + | |
495 | + // to get Stream - Head | |
496 | + protected void readHeader() { | |
497 | + String id = ""; | |
498 | + for (int i = 0; i < 6; i++) { | |
499 | + id += (char) read(); | |
500 | + } | |
501 | + if (!id.startsWith("GIF")) { | |
502 | + status = STATUS_FORMAT_ERROR; | |
503 | + return; | |
504 | + } | |
505 | + readLSD(); | |
506 | + if (gctFlag && !err()) { | |
507 | + gct = readColorTable(gctSize); | |
508 | + bgColor = gct[bgIndex]; | |
509 | + } | |
510 | + } | |
511 | + | |
512 | + protected void readImage() { | |
513 | + // offset of X | |
514 | + ix = readShort(); // (sub)image position & size | |
515 | + // offset of Y | |
516 | + iy = readShort(); | |
517 | + // width of bitmap | |
518 | + iw = readShort(); | |
519 | + // height of bitmap | |
520 | + ih = readShort(); | |
521 | + | |
522 | + // Local Color Table Flag | |
523 | + int packed = read(); | |
524 | + lctFlag = (packed & 0x80) != 0; // 1 - local color table flag | |
525 | + | |
526 | + // Interlace Flag, to array with interwoven if ENABLE, with order | |
527 | + // otherwise | |
528 | + interlace = (packed & 0x40) != 0; // 2 - interlace flag | |
529 | + // 3 - sort flag | |
530 | + // 4-5 - reserved | |
531 | + lctSize = 2 << (packed & 7); // 6-8 - local color table size | |
532 | + if (lctFlag) { | |
533 | + lct = readColorTable(lctSize); // read table | |
534 | + act = lct; // make local table active | |
535 | + } else { | |
536 | + act = gct; // make global table active | |
537 | + if (bgIndex == transIndex) { | |
538 | + bgColor = 0; | |
539 | + } | |
540 | + } | |
541 | + int save = 0; | |
542 | + if (transparency) { | |
543 | + save = act[transIndex]; | |
544 | + act[transIndex] = 0; // set transparent color if specified | |
545 | + } | |
546 | + if (act == null) { | |
547 | + status = STATUS_FORMAT_ERROR; // no color table defined | |
548 | + } | |
549 | + if (err()) { | |
550 | + return; | |
551 | + } | |
552 | + decodeImageData(); // decode pixel data | |
553 | + skip(); | |
554 | + if (err()) { | |
555 | + return; | |
556 | + } | |
557 | + frameCount++; | |
558 | + // create new image to receive frame data | |
559 | + image = Bitmap.createBitmap(width, height, Config.ARGB_4444); | |
560 | + // createImage(width, height); | |
561 | + setPixels(); // transfer pixel data to image | |
562 | + frames.addElement(new GifFrame(image, delay)); // add image to frame | |
563 | + // list | |
564 | + if (transparency) { | |
565 | + act[transIndex] = save; | |
566 | + } | |
567 | + resetFrame(); | |
568 | + } | |
569 | + | |
570 | + // Logical Screen Descriptor | |
571 | + protected void readLSD() { | |
572 | + // logical screen size | |
573 | + width = readShort(); | |
574 | + height = readShort(); | |
575 | + // packed fields | |
576 | + int packed = read(); | |
577 | + gctFlag = (packed & 0x80) != 0; // 1 : global color table flag | |
578 | + // 2-4 : color resolution | |
579 | + // 5 : gct sort flag | |
580 | + gctSize = 2 << (packed & 7); // 6-8 : gct size | |
581 | + bgIndex = read(); // background color index | |
582 | + pixelAspect = read(); // pixel aspect ratio | |
583 | + } | |
584 | + | |
585 | + protected void readNetscapeExt() { | |
586 | + do { | |
587 | + readBlock(); | |
588 | + if (block[0] == 1) { | |
589 | + // loop count sub-block | |
590 | + int b1 = ((int) block[1]) & 0xff; | |
591 | + int b2 = ((int) block[2]) & 0xff; | |
592 | + loopCount = (b2 << 8) | b1; | |
593 | + } | |
594 | + } while ((blockSize > 0) && !err()); | |
595 | + } | |
596 | + | |
597 | + // read 8 bit data | |
598 | + protected int readShort() { | |
599 | + // read 16-bit value, LSB first | |
600 | + return read() | (read() << 8); | |
601 | + } | |
602 | + | |
603 | + protected void resetFrame() { | |
604 | + lastDispose = dispose; | |
605 | + lrx = ix; | |
606 | + lry = iy; | |
607 | + lrw = iw; | |
608 | + lrh = ih; | |
609 | + lastImage = image; | |
610 | + lastBgColor = bgColor; | |
611 | + dispose = 0; | |
612 | + transparency = false; | |
613 | + delay = 0; | |
614 | + lct = null; | |
615 | + } | |
616 | + | |
617 | + /** | |
618 | + * Skips variable length blocks up to and including next zero length block. | |
619 | + */ | |
620 | + protected void skip() { | |
621 | + do { | |
622 | + readBlock(); | |
623 | + } while ((blockSize > 0) && !err()); | |
624 | + } | |
625 | +} | ... | ... |
... | ... | @@ -0,0 +1,61 @@ |
1 | +package com.shunzhi.mychartlibrary.utils; | |
2 | + | |
3 | +import android.annotation.SuppressLint; | |
4 | +import android.graphics.Bitmap; | |
5 | +import android.graphics.BitmapFactory; | |
6 | +import android.os.Build; | |
7 | + | |
8 | +import java.io.BufferedInputStream; | |
9 | +import java.io.ByteArrayOutputStream; | |
10 | +import java.io.FileInputStream; | |
11 | +import java.io.FileNotFoundException; | |
12 | +import java.io.IOException; | |
13 | + | |
14 | +public class ImageCheckoutUtil { | |
15 | + /** | |
16 | + * 检测图片内存大小 | |
17 | + * | |
18 | + * @param data | |
19 | + * @return | |
20 | + */ | |
21 | + @SuppressLint("NewApi") | |
22 | + public static int getImageSize(Bitmap data) { | |
23 | + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR1) { | |
24 | + return data.getRowBytes() * data.getHeight(); | |
25 | + } else { | |
26 | + return data.getByteCount(); | |
27 | + } | |
28 | + } | |
29 | + | |
30 | + public static Bitmap getLoacalBitmap(String url) { | |
31 | + try { | |
32 | + ByteArrayOutputStream out; | |
33 | + FileInputStream fis = new FileInputStream(url); | |
34 | + BufferedInputStream bis = new BufferedInputStream(fis); | |
35 | + out = new ByteArrayOutputStream(); | |
36 | + @SuppressWarnings("unused") | |
37 | + int hasRead = 0; | |
38 | + byte[] buffer = new byte[1024 * 2]; | |
39 | + while ((hasRead = bis.read(buffer)) > 0) { | |
40 | + // 读出多少数据,向输出流中写入多少 | |
41 | + out.write(buffer); | |
42 | + out.flush(); | |
43 | + } | |
44 | + out.close(); | |
45 | + fis.close(); | |
46 | + bis.close(); | |
47 | + byte[] data = out.toByteArray(); | |
48 | + // 长宽减半 | |
49 | + BitmapFactory.Options opts = new BitmapFactory.Options(); | |
50 | + opts.inSampleSize = 3; | |
51 | + return BitmapFactory.decodeByteArray(data, 0, data.length, opts); | |
52 | + } catch (FileNotFoundException e) { | |
53 | + e.printStackTrace(); | |
54 | + return null; | |
55 | + } catch (IOException e) { | |
56 | + // TODO Auto-generated catch block | |
57 | + e.printStackTrace(); | |
58 | + return null; | |
59 | + } | |
60 | + } | |
61 | +} | ... | ... |
... | ... | @@ -0,0 +1,26 @@ |
1 | +package com.shunzhi.mychartlibrary.utils; | |
2 | + | |
3 | +import android.content.Context; | |
4 | +import android.view.View; | |
5 | +import android.view.inputmethod.InputMethodManager; | |
6 | + | |
7 | +/** | |
8 | + * Created by Mao Jiqing on 2016/9/28. | |
9 | + */ | |
10 | +public class KeyBoardUtils { | |
11 | + public static void hideKeyBoard(Context context, View view) { | |
12 | + InputMethodManager imm = (InputMethodManager) context | |
13 | + .getSystemService(Context.INPUT_METHOD_SERVICE); | |
14 | + imm.hideSoftInputFromWindow(view.getWindowToken(), 0); // 强制隐藏键盘 | |
15 | + } | |
16 | + | |
17 | + public static void showKeyBoard(Context context, View view) { | |
18 | + view.setFocusable(true); | |
19 | + view.setFocusableInTouchMode(true); | |
20 | + view.requestFocus(); | |
21 | + view.findFocus(); | |
22 | + InputMethodManager imm = (InputMethodManager) context | |
23 | + .getSystemService(Context.INPUT_METHOD_SERVICE); | |
24 | + imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS); | |
25 | + } | |
26 | +} | ... | ... |
... | ... | @@ -0,0 +1,157 @@ |
1 | +package com.shunzhi.mychartlibrary.utils; | |
2 | + | |
3 | +import java.io.ByteArrayInputStream; | |
4 | +import java.io.ByteArrayOutputStream; | |
5 | +import java.io.IOException; | |
6 | + | |
7 | +import android.graphics.Bitmap; | |
8 | +import android.graphics.BitmapFactory; | |
9 | +import android.graphics.Matrix; | |
10 | +import android.media.ExifInterface; | |
11 | + | |
12 | +public class PictureUtil { | |
13 | + | |
14 | + /** | |
15 | + * 计算图片的缩放值 | |
16 | + * | |
17 | + * @param options | |
18 | + * @param reqWidth | |
19 | + * @param reqHeight | |
20 | + * @return | |
21 | + */ | |
22 | + public static int calculateInSampleSize(BitmapFactory.Options options, | |
23 | + int reqWidth, int reqHeight) { | |
24 | + // Raw height and width of image | |
25 | + final int height = options.outHeight; | |
26 | + final int width = options.outWidth; | |
27 | + int inSampleSize = 1; | |
28 | + | |
29 | + if (height > reqHeight || width > reqWidth) { | |
30 | + | |
31 | + // Calculate ratios of height and width to requested height and | |
32 | + // width | |
33 | + final int heightRatio = Math.round((float) height | |
34 | + / (float) reqHeight); | |
35 | + final int widthRatio = Math.round((float) width / (float) reqWidth); | |
36 | + | |
37 | + // Choose the smallest ratio as inSampleSize value, this will | |
38 | + // guarantee | |
39 | + // a final image with both dimensions larger than or equal to the | |
40 | + // requested height and width. | |
41 | + inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; | |
42 | + } | |
43 | + | |
44 | + return inSampleSize; | |
45 | + } | |
46 | + | |
47 | + /** | |
48 | + * 根据路径获得图片并压缩返回bitmap用于显示 | |
49 | + * | |
50 | + * @param imagesrc | |
51 | + * @return | |
52 | + */ | |
53 | + public static Bitmap getSmallBitmap(String filePath) { | |
54 | + final BitmapFactory.Options options = new BitmapFactory.Options(); | |
55 | + options.inJustDecodeBounds = true; | |
56 | + BitmapFactory.decodeFile(filePath, options); | |
57 | + | |
58 | + // Calculate inSampleSize | |
59 | + options.inSampleSize = calculateInSampleSize(options, 320, 480); | |
60 | + | |
61 | + // Decode bitmap with inSampleSize set | |
62 | + options.inJustDecodeBounds = false; | |
63 | + | |
64 | + return BitmapFactory.decodeFile(filePath, options); | |
65 | + } | |
66 | + | |
67 | + /** | |
68 | + * 压缩大图片 | |
69 | + * @param srcPath | |
70 | + * @return | |
71 | + */ | |
72 | + public static Bitmap compressSizeImage(String srcPath) { | |
73 | + BitmapFactory.Options newOpts = new BitmapFactory.Options(); | |
74 | + //开始读入图片,此时把options.inJustDecodeBounds 设回true了 | |
75 | + newOpts.inJustDecodeBounds = true; | |
76 | + Bitmap bitmap = BitmapFactory.decodeFile(srcPath,newOpts);//此时返回bm为空 | |
77 | + | |
78 | + newOpts.inJustDecodeBounds = false; | |
79 | + int w = newOpts.outWidth; | |
80 | + int h = newOpts.outHeight; | |
81 | + //现在主流手机比较多是800*480分辨率,所以高和宽我们设置为 | |
82 | + float hh = 800f;//这里设置高度为800f | |
83 | + float ww = 480f;//这里设置宽度为480f | |
84 | + //缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可 | |
85 | + int be = 1;//be=1表示不缩放 | |
86 | + if (w > h && w > ww) {//如果宽度大的话根据宽度固定大小缩放 | |
87 | + be = (int) (newOpts.outWidth / ww); | |
88 | + } else if (w < h && h > hh) {//如果高度高的话根据宽度固定大小缩放 | |
89 | + be = (int) (newOpts.outHeight / hh); | |
90 | + } | |
91 | + if (be <= 0) | |
92 | + be = 1; | |
93 | + newOpts.inSampleSize = be;//设置缩放比例 | |
94 | + //重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了 | |
95 | + bitmap = BitmapFactory.decodeFile(srcPath, newOpts); | |
96 | + return compressImage(bitmap);//压缩好比例大小后再进行质量压缩 | |
97 | + } | |
98 | + | |
99 | + public static Bitmap compressImage(Bitmap image) { | |
100 | + | |
101 | + ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |
102 | + image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中 | |
103 | + int options = 100; | |
104 | + while ( baos.toByteArray().length / 1024>100) { //循环判断如果压缩后图片是否大于100kb,大于继续压缩 | |
105 | + baos.reset();//重置baos即清空baos | |
106 | + image.compress(Bitmap.CompressFormat.JPEG, options, baos);//这里压缩options%,把压缩后的数据存放到baos中 | |
107 | + options -= 10;//每次都减少10 | |
108 | + } | |
109 | + ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream中 | |
110 | + Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);//把ByteArrayInputStream数据生成图片 | |
111 | + return bitmap; | |
112 | + } | |
113 | + | |
114 | + /** | |
115 | + * 获取图片文件的信息,是否旋转了90度,如果是则反转 | |
116 | + * @param bitmap 需要旋转的图片 | |
117 | + * @param path 图片的路径 | |
118 | + */ | |
119 | + public static Bitmap reviewPicRotate(Bitmap bitmap,String path){ | |
120 | + int degree = getPicRotate(path); | |
121 | + if(degree!=0){ | |
122 | + Matrix m = new Matrix(); | |
123 | + int width = bitmap.getWidth(); | |
124 | + int height = bitmap.getHeight(); | |
125 | + m.setRotate(degree); // 旋转angle度 | |
126 | + bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height,m, true);// 从新生成图片 | |
127 | + } | |
128 | + return bitmap; | |
129 | + } | |
130 | + | |
131 | + /** | |
132 | + * 读取图片文件旋转的角度 | |
133 | + * @param path 图片绝对路径 | |
134 | + * @return 图片旋转的角度 | |
135 | + */ | |
136 | + public static int getPicRotate(String path) { | |
137 | + int degree = 0; | |
138 | + try { | |
139 | + ExifInterface exifInterface = new ExifInterface(path); | |
140 | + int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); | |
141 | + switch (orientation) { | |
142 | + case ExifInterface.ORIENTATION_ROTATE_90: | |
143 | + degree = 90; | |
144 | + break; | |
145 | + case ExifInterface.ORIENTATION_ROTATE_180: | |
146 | + degree = 180; | |
147 | + break; | |
148 | + case ExifInterface.ORIENTATION_ROTATE_270: | |
149 | + degree = 270; | |
150 | + break; | |
151 | + } | |
152 | + } catch (IOException e) { | |
153 | + e.printStackTrace(); | |
154 | + } | |
155 | + return degree; | |
156 | + } | |
157 | +} | ... | ... |
... | ... | @@ -0,0 +1,239 @@ |
1 | +package com.shunzhi.mychartlibrary.utils; | |
2 | + | |
3 | +import android.annotation.TargetApi; | |
4 | +import android.app.Activity; | |
5 | +import android.content.Context; | |
6 | +import android.content.res.Configuration; | |
7 | +import android.content.res.Resources; | |
8 | +import android.os.Build; | |
9 | +import android.util.DisplayMetrics; | |
10 | +import android.view.Display; | |
11 | +import android.view.ViewConfiguration; | |
12 | +import android.view.Window; | |
13 | +import android.view.WindowManager; | |
14 | + | |
15 | +import java.lang.reflect.Field; | |
16 | +import java.lang.reflect.Method; | |
17 | + | |
18 | +public class ScreenUtil { | |
19 | + | |
20 | + private static int screenWidth = 0; | |
21 | + | |
22 | + private static int screenHeight = 0; | |
23 | + private static int screenTotalHeight = 0; | |
24 | + private static int statusBarHeight = 0; | |
25 | + | |
26 | + private static final int TITLE_HEIGHT = 0; | |
27 | + | |
28 | + /** | |
29 | + */ | |
30 | + public static int dip2px(Context context, float dpValue) { | |
31 | + final float scale = context.getResources().getDisplayMetrics().density; | |
32 | + return (int) (dpValue * scale + 0.5f); | |
33 | + } | |
34 | + | |
35 | + /** | |
36 | + */ | |
37 | + public static int px2dip(Context context, float pxValue) { | |
38 | + final float scale = context.getResources().getDisplayMetrics().density; | |
39 | + return (int) (pxValue / scale + 0.5f); | |
40 | + } | |
41 | + | |
42 | + public static int getScreenWidth(Context context) { | |
43 | +// if (screenWidth != 0) { | |
44 | +// return screenWidth; | |
45 | +// } | |
46 | + DisplayMetrics dm = new DisplayMetrics(); | |
47 | + WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); | |
48 | + wm.getDefaultDisplay().getMetrics(dm); | |
49 | + screenWidth = dm.widthPixels; | |
50 | + return screenWidth; | |
51 | + } | |
52 | + | |
53 | + public static int getScreenHeight(Context context) { | |
54 | +// if (screenHeight != 0) { | |
55 | +// return screenHeight; | |
56 | +// } | |
57 | + int top = 0; | |
58 | + if (context instanceof Activity) { | |
59 | + top = ((Activity) context).getWindow().findViewById(Window.ID_ANDROID_CONTENT).getTop(); | |
60 | + if (top == 0) { | |
61 | + top = (int) (TITLE_HEIGHT * getScreenDensity(context)); | |
62 | + } | |
63 | + } | |
64 | + DisplayMetrics dm = new DisplayMetrics(); | |
65 | + WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); | |
66 | + wm.getDefaultDisplay().getMetrics(dm); | |
67 | + screenHeight = dm.heightPixels - top; | |
68 | + return screenHeight; | |
69 | + } | |
70 | + | |
71 | + public static int getScreenTotalHeight(Context context) { | |
72 | + if (screenTotalHeight != 0) { | |
73 | + return screenTotalHeight; | |
74 | + } | |
75 | + DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); | |
76 | + screenTotalHeight = displayMetrics.heightPixels; | |
77 | + return screenTotalHeight; | |
78 | + } | |
79 | + public static float getScreenDensity(Context context) { | |
80 | + WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); | |
81 | + DisplayMetrics metric = new DisplayMetrics(); | |
82 | + wm.getDefaultDisplay().getMetrics(metric); | |
83 | + return metric.density; | |
84 | + } | |
85 | + | |
86 | + public static float getScreenDensityDpi(Context context) { | |
87 | + WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); | |
88 | + DisplayMetrics metric = new DisplayMetrics(); | |
89 | + wm.getDefaultDisplay().getMetrics(metric); | |
90 | + return metric.densityDpi; | |
91 | + } | |
92 | + public static int getStatusBarHeight(Context context) { | |
93 | + if (statusBarHeight != 0) { | |
94 | + return statusBarHeight; | |
95 | + } | |
96 | + Class<?> c = null; | |
97 | + Object obj = null; | |
98 | + Field field = null; | |
99 | + int x = 0; | |
100 | + try { | |
101 | + c = Class.forName("com.android.internal.R$dimen"); | |
102 | + obj = c.newInstance(); | |
103 | + field = c.getField("status_bar_height"); | |
104 | + x = Integer.parseInt(field.get(obj).toString()); | |
105 | + statusBarHeight = context.getResources().getDimensionPixelSize(x); | |
106 | + } catch (Exception e1) { | |
107 | + e1.printStackTrace(); | |
108 | + } | |
109 | + return statusBarHeight; | |
110 | + } | |
111 | + public static boolean isTablet(Context context) { | |
112 | + return (context.getResources().getConfiguration().screenLayout | |
113 | + & Configuration.SCREENLAYOUT_SIZE_MASK) | |
114 | + >= Configuration.SCREENLAYOUT_SIZE_LARGE; | |
115 | + } | |
116 | + | |
117 | + | |
118 | + //获取屏幕原始尺寸高度,包括虚拟功能键高度 | |
119 | + public static int getDpi(Context context){ | |
120 | + int dpi = 0; | |
121 | + WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); | |
122 | + Display display = windowManager.getDefaultDisplay(); | |
123 | + DisplayMetrics displayMetrics = new DisplayMetrics(); | |
124 | + @SuppressWarnings("rawtypes") | |
125 | + Class c; | |
126 | + try { | |
127 | + c = Class.forName("android.view.Display"); | |
128 | + @SuppressWarnings("unchecked") | |
129 | + Method method = c.getMethod("getRealMetrics",DisplayMetrics.class); | |
130 | + method.invoke(display, displayMetrics); | |
131 | + dpi=displayMetrics.heightPixels; | |
132 | + }catch(Exception e){ | |
133 | + e.printStackTrace(); | |
134 | + } | |
135 | + return dpi; | |
136 | + } | |
137 | + | |
138 | + /** | |
139 | + * 获取 虚拟按键的高度 | |
140 | + * @param context | |
141 | + * @return | |
142 | + */ | |
143 | + public static int getBottomStatusHeight(Context context){ | |
144 | + int totalHeight = getDpi(context); | |
145 | + | |
146 | + int contentHeight = getScreenHeight(context); | |
147 | + | |
148 | + return totalHeight - contentHeight; | |
149 | + } | |
150 | + | |
151 | + /** | |
152 | + * 标题栏高度 | |
153 | + * @return | |
154 | + */ | |
155 | + public static int getTitleHeight(Activity activity){ | |
156 | + return activity.getWindow().findViewById(Window.ID_ANDROID_CONTENT).getTop(); | |
157 | + } | |
158 | + | |
159 | + /** | |
160 | + * 获得状态栏的高度 | |
161 | + * | |
162 | + * @param context | |
163 | + * @return | |
164 | + */ | |
165 | + public static int getStatusHeight(Context context) | |
166 | + { | |
167 | + | |
168 | + int statusHeight = -1; | |
169 | + try | |
170 | + { | |
171 | + Class<?> clazz = Class.forName("com.android.internal.R$dimen"); | |
172 | + Object object = clazz.newInstance(); | |
173 | + int height = Integer.parseInt(clazz.getField("status_bar_height") | |
174 | + .get(object).toString()); | |
175 | + statusHeight = context.getResources().getDimensionPixelSize(height); | |
176 | + } catch (Exception e) | |
177 | + { | |
178 | + e.printStackTrace(); | |
179 | + } | |
180 | + return statusHeight; | |
181 | + } | |
182 | + | |
183 | + //获取虚拟按键的高度 | |
184 | + public static int getNavigationBarHeight(Context context) { | |
185 | + int result = 0; | |
186 | + if (hasNavBar(context)) { | |
187 | + Resources res = context.getResources(); | |
188 | + int resourceId = res.getIdentifier("navigation_bar_height", "dimen", "android"); | |
189 | + if (resourceId > 0) { | |
190 | + result = res.getDimensionPixelSize(resourceId); | |
191 | + } | |
192 | + } | |
193 | + return result; | |
194 | + } | |
195 | + | |
196 | + /** | |
197 | + * 检查是否存在虚拟按键栏 | |
198 | + * | |
199 | + * @param context | |
200 | + * @return | |
201 | + */ | |
202 | + @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) | |
203 | + public static boolean hasNavBar(Context context) { | |
204 | + Resources res = context.getResources(); | |
205 | + int resourceId = res.getIdentifier("config_showNavigationBar", "bool", "android"); | |
206 | + if (resourceId != 0) { | |
207 | + boolean hasNav = res.getBoolean(resourceId); | |
208 | + // check override flag | |
209 | + String sNavBarOverride = getNavBarOverride(); | |
210 | + if ("1".equals(sNavBarOverride)) { | |
211 | + hasNav = false; | |
212 | + } else if ("0".equals(sNavBarOverride)) { | |
213 | + hasNav = true; | |
214 | + } | |
215 | + return hasNav; | |
216 | + } else { // fallback | |
217 | + return !ViewConfiguration.get(context).hasPermanentMenuKey(); | |
218 | + } | |
219 | + } | |
220 | + | |
221 | + /** | |
222 | + * 判断虚拟按键栏是否重写 | |
223 | + * | |
224 | + * @return | |
225 | + */ | |
226 | + private static String getNavBarOverride() { | |
227 | + String sNavBarOverride = null; | |
228 | + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { | |
229 | + try { | |
230 | + Class c = Class.forName("android.os.SystemProperties"); | |
231 | + Method m = c.getDeclaredMethod("get", String.class); | |
232 | + m.setAccessible(true); | |
233 | + sNavBarOverride = (String) m.invoke(null, "qemu.hw.mainkeys"); | |
234 | + } catch (Throwable e) { | |
235 | + } | |
236 | + } | |
237 | + return sNavBarOverride; | |
238 | + } | |
239 | +} | |
0 | 240 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,68 @@ |
1 | +package com.shunzhi.mychartlibrary.utils; | |
2 | + | |
3 | +import android.content.Context; | |
4 | +import android.content.SharedPreferences; | |
5 | + | |
6 | +/** | |
7 | + * Created by Mao Jiqing on 2016/10/10. | |
8 | + */ | |
9 | +public class SharedPreferencesUtils { | |
10 | + /** | |
11 | + * 保存在手机里面的文件名 | |
12 | + */ | |
13 | + private static final String FILE_NAME = "share_date"; | |
14 | + | |
15 | + /** | |
16 | + * 保存数据的方法,我们需要拿到保存数据的具体类型,然后根据类型调用不同的保存方法 | |
17 | + * | |
18 | + * @param context | |
19 | + * @param key | |
20 | + * @param object | |
21 | + */ | |
22 | + public static void setParam(Context context, String key, Object object) { | |
23 | + | |
24 | + String type = object.getClass().getSimpleName(); | |
25 | + SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); | |
26 | + SharedPreferences.Editor editor = sp.edit(); | |
27 | + | |
28 | + if ("String".equals(type)) { | |
29 | + editor.putString(key, (String) object); | |
30 | + } else if ("Integer".equals(type)) { | |
31 | + editor.putInt(key, (Integer) object); | |
32 | + } else if ("Boolean".equals(type)) { | |
33 | + editor.putBoolean(key, (Boolean) object); | |
34 | + } else if ("Float".equals(type)) { | |
35 | + editor.putFloat(key, (Float) object); | |
36 | + } else if ("Long".equals(type)) { | |
37 | + editor.putLong(key, (Long) object); | |
38 | + } | |
39 | + | |
40 | + editor.commit(); | |
41 | + } | |
42 | + | |
43 | + /** | |
44 | + * 得到保存数据的方法,我们根据默认值得到保存的数据的具体类型,然后调用相对于的方法获取值 | |
45 | + * | |
46 | + * @param context | |
47 | + * @param key | |
48 | + * @param defaultObject | |
49 | + * @return | |
50 | + */ | |
51 | + public static Object getParam(Context context, String key, Object defaultObject) { | |
52 | + String type = defaultObject.getClass().getSimpleName(); | |
53 | + SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); | |
54 | + | |
55 | + if ("String".equals(type)) { | |
56 | + return sp.getString(key, (String) defaultObject); | |
57 | + } else if ("Integer".equals(type)) { | |
58 | + return sp.getInt(key, (Integer) defaultObject); | |
59 | + } else if ("Boolean".equals(type)) { | |
60 | + return sp.getBoolean(key, (Boolean) defaultObject); | |
61 | + } else if ("Float".equals(type)) { | |
62 | + return sp.getFloat(key, (Float) defaultObject); | |
63 | + } else if ("Long".equals(type)) { | |
64 | + return sp.getLong(key, (Long) defaultObject); | |
65 | + } | |
66 | + return null; | |
67 | + } | |
68 | +} | ... | ... |
... | ... | @@ -0,0 +1,178 @@ |
1 | +/** | |
2 | + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
8 | + * Unless required by applicable law or agrtbd to in writing, software | |
9 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
10 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
11 | + * Stb the License for the specific language governing permissions and | |
12 | + * limitations under the License. | |
13 | + */ | |
14 | +package com.shunzhi.mychartlibrary.utils; | |
15 | + | |
16 | +import android.content.Context; | |
17 | +import android.text.Spannable; | |
18 | +import android.text.Spannable.Factory; | |
19 | +import android.text.style.ImageSpan; | |
20 | + | |
21 | + | |
22 | +import com.shunzhi.mychartlibrary.R; | |
23 | + | |
24 | +import java.util.HashMap; | |
25 | +import java.util.Map; | |
26 | +import java.util.Map.Entry; | |
27 | +import java.util.regex.Matcher; | |
28 | +import java.util.regex.Pattern; | |
29 | + | |
30 | +public class SmileUtils { | |
31 | + public static final String f1 = "[:f1]"; | |
32 | + public static final String f2 = "[:f2]"; | |
33 | + public static final String f3 = "[:f3]"; | |
34 | + public static final String f4 = "[:f4]"; | |
35 | + public static final String f5 = "[:f5]"; | |
36 | + public static final String f6 = "[:f6]"; | |
37 | + public static final String f7 = "[:f7]"; | |
38 | + public static final String f8 = "[:f8]"; | |
39 | + public static final String f9 = "[:f9]"; | |
40 | + public static final String f10 = "[:f10]"; | |
41 | + public static final String f11 = "[:f11]"; | |
42 | + public static final String f12 = "[:f12]"; | |
43 | + public static final String f13 = "[:f13]"; | |
44 | + public static final String f14 = "[:f14]"; | |
45 | + public static final String f15 = "[:f15]"; | |
46 | + public static final String f16 = "[:f16]"; | |
47 | + public static final String f17 = "[:f17]"; | |
48 | + public static final String f18 = "[:f18]"; | |
49 | + public static final String f19 = "[:f19]"; | |
50 | + public static final String f20 = "[:f20]"; | |
51 | + public static final String f21 = "[:f21]"; | |
52 | + public static final String f22 = "[:f22]"; | |
53 | + public static final String f23 = "[:f23]"; | |
54 | + public static final String f24 = "[:f24]"; | |
55 | + public static final String f25 = "[:f25]"; | |
56 | + public static final String f26 = "[:f26]"; | |
57 | + public static final String f27 = "[:f27]"; | |
58 | + public static final String f28 = "[:f28]"; | |
59 | + public static final String f29 = "[:f29]"; | |
60 | + public static final String f30 = "[:f30]"; | |
61 | + public static final String f31 = "[:f31]"; | |
62 | + public static final String f32 = "[:f32]"; | |
63 | + public static final String f33 = "[:f33]"; | |
64 | + public static final String f34 = "[:f34]"; | |
65 | + public static final String f35 = "[:f35]"; | |
66 | + public static final String f36 = "[:f36]"; | |
67 | + public static final String f37 = "[:f37]"; | |
68 | + public static final String f38 = "[:f38]"; | |
69 | + public static final String f39 = "[:f39]"; | |
70 | + public static final String f40 = "[:f40]"; | |
71 | + | |
72 | + private static final Factory spannableFactory = Factory | |
73 | + .getInstance(); | |
74 | + | |
75 | + private static final Map<Pattern, Integer> emoticons = new HashMap<Pattern, Integer>(); | |
76 | + | |
77 | + static { | |
78 | + | |
79 | + addPattern(emoticons, f1, R.mipmap.f1); | |
80 | + addPattern(emoticons, f2, R.mipmap.f2); | |
81 | + addPattern(emoticons, f3, R.mipmap.f3); | |
82 | + addPattern(emoticons, f4, R.mipmap.f4); | |
83 | + addPattern(emoticons, f5, R.mipmap.f5); | |
84 | + addPattern(emoticons, f6, R.mipmap.f6); | |
85 | + addPattern(emoticons, f7, R.mipmap.f7); | |
86 | + addPattern(emoticons, f8, R.mipmap.f8); | |
87 | + addPattern(emoticons, f9, R.mipmap.f9); | |
88 | + addPattern(emoticons, f10, R.mipmap.f10); | |
89 | + addPattern(emoticons, f11, R.mipmap.f11); | |
90 | + addPattern(emoticons, f12, R.mipmap.f12); | |
91 | + addPattern(emoticons, f13, R.mipmap.f13); | |
92 | + addPattern(emoticons, f14, R.mipmap.f14); | |
93 | + addPattern(emoticons, f15, R.mipmap.f15); | |
94 | + addPattern(emoticons, f16, R.mipmap.f16); | |
95 | + addPattern(emoticons, f17, R.mipmap.f17); | |
96 | + addPattern(emoticons, f18, R.mipmap.f18); | |
97 | + addPattern(emoticons, f19, R.mipmap.f19); | |
98 | + addPattern(emoticons, f20, R.mipmap.f20); | |
99 | + addPattern(emoticons, f21, R.mipmap.f21); | |
100 | + addPattern(emoticons, f22, R.mipmap.f22); | |
101 | + addPattern(emoticons, f23, R.mipmap.f23); | |
102 | + addPattern(emoticons, f24, R.mipmap.f24); | |
103 | + addPattern(emoticons, f25, R.mipmap.f25); | |
104 | + addPattern(emoticons, f26, R.mipmap.f26); | |
105 | + addPattern(emoticons, f27, R.mipmap.f27); | |
106 | + addPattern(emoticons, f28, R.mipmap.f28); | |
107 | + addPattern(emoticons, f29, R.mipmap.f29); | |
108 | + addPattern(emoticons, f30, R.mipmap.f30); | |
109 | + addPattern(emoticons, f31, R.mipmap.f31); | |
110 | + addPattern(emoticons, f32, R.mipmap.f32); | |
111 | + addPattern(emoticons, f33, R.mipmap.f33); | |
112 | + addPattern(emoticons, f34, R.mipmap.f34); | |
113 | + addPattern(emoticons, f35, R.mipmap.f35); | |
114 | + addPattern(emoticons, f36, R.mipmap.f36); | |
115 | + addPattern(emoticons, f37, R.mipmap.f37); | |
116 | + addPattern(emoticons, f38, R.mipmap.f38); | |
117 | + addPattern(emoticons, f39, R.mipmap.f39); | |
118 | + addPattern(emoticons, f40, R.mipmap.f40); | |
119 | + } | |
120 | + | |
121 | + private static void addPattern(Map<Pattern, Integer> map, String smile, | |
122 | + int resource) { | |
123 | + map.put(Pattern.compile(Pattern.quote(smile)), resource); | |
124 | + } | |
125 | + | |
126 | + /** | |
127 | + * replace existing spannable with smiles | |
128 | + * | |
129 | + * @param context | |
130 | + * @param spannable | |
131 | + * @return | |
132 | + */ | |
133 | + public static boolean addSmiles(Context context, Spannable spannable) { | |
134 | + boolean hasChanges = false; | |
135 | + for (Entry<Pattern, Integer> entry : emoticons.entrySet()) { | |
136 | + Matcher matcher = entry.getKey().matcher(spannable); | |
137 | + while (matcher.find()) { | |
138 | + boolean set = true; | |
139 | + for (ImageSpan span : spannable.getSpans(matcher.start(), | |
140 | + matcher.end(), ImageSpan.class)) | |
141 | + if (spannable.getSpanStart(span) >= matcher.start() | |
142 | + && spannable.getSpanEnd(span) <= matcher.end()) | |
143 | + spannable.removeSpan(span); | |
144 | + else { | |
145 | + set = false; | |
146 | + break; | |
147 | + } | |
148 | + if (set) { | |
149 | + hasChanges = true; | |
150 | + spannable.setSpan(new ImageSpan(context, entry.getValue()), | |
151 | + matcher.start(), matcher.end(), | |
152 | + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); | |
153 | + } | |
154 | + } | |
155 | + } | |
156 | + return hasChanges; | |
157 | + } | |
158 | + | |
159 | + public static Spannable getSmiledText(Context context, CharSequence text) { | |
160 | + Spannable spannable = spannableFactory.newSpannable(text); | |
161 | + addSmiles(context, spannable); | |
162 | + return spannable; | |
163 | + } | |
164 | + | |
165 | + public static boolean containsKey(String key) { | |
166 | + boolean b = false; | |
167 | + for (Entry<Pattern, Integer> entry : emoticons.entrySet()) { | |
168 | + Matcher matcher = entry.getKey().matcher(key); | |
169 | + if (matcher.find()) { | |
170 | + b = true; | |
171 | + break; | |
172 | + } | |
173 | + } | |
174 | + | |
175 | + return b; | |
176 | + } | |
177 | + | |
178 | +} | ... | ... |
... | ... | @@ -0,0 +1,140 @@ |
1 | +package com.shunzhi.mychartlibrary.utils; | |
2 | + | |
3 | +import android.app.Activity; | |
4 | +import android.content.Context; | |
5 | +import android.graphics.Color; | |
6 | +import android.os.Build; | |
7 | +import android.support.annotation.ColorInt; | |
8 | +import android.support.v7.widget.Toolbar; | |
9 | +import android.view.View; | |
10 | +import android.view.ViewGroup; | |
11 | +import android.view.Window; | |
12 | +import android.view.WindowManager; | |
13 | + | |
14 | +import java.lang.reflect.Field; | |
15 | + | |
16 | + | |
17 | +/** | |
18 | + * Created by Horrarndoo on 2017/8/31. | |
19 | + * <p> | |
20 | + * StatusBar工具类 | |
21 | + */ | |
22 | +public class StatusBarUtils { | |
23 | + | |
24 | + private static final int DEFAULT_STATUS_BAR_ALPHA = 0; | |
25 | + | |
26 | + /** | |
27 | + * 设置状态栏颜色 | |
28 | + * | |
29 | + * @param activity 需要设置的 activity | |
30 | + * @param color 状态栏颜色值 | |
31 | + */ | |
32 | + public static void setColor(Activity activity, @ColorInt int color) { | |
33 | + setBarColor(activity, color); | |
34 | + } | |
35 | + | |
36 | + /** | |
37 | + * 设置状态栏背景色 | |
38 | + * 4.4以下不处理 | |
39 | + * 4.4使用默认沉浸式状态栏 | |
40 | + * | |
41 | + * @param color 要为状态栏设置的颜色值 | |
42 | + */ | |
43 | + public static void setBarColor(Activity activity, int color) { | |
44 | + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { | |
45 | + Window win = activity.getWindow(); | |
46 | + View decorView = win.getDecorView(); | |
47 | + win.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);//沉浸式状态栏(4.4-5.0透明,5.0以上半透明) | |
48 | + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {//android5.0以上设置透明效果 | |
49 | + win.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);//清除flag,为了android5.0以上也全透明效果 | |
50 | + //让应用的主体内容占用系统状态栏的空间 | |
51 | +// int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | |
52 | +// | View.SYSTEM_UI_FLAG_LAYOUT_STABLE; | |
53 | + int option = View.SYSTEM_UI_FLAG_LAYOUT_STABLE; | |
54 | + decorView.setSystemUiVisibility(decorView.getSystemUiVisibility() | option); | |
55 | + win.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); | |
56 | + win.setStatusBarColor(color);//设置状态栏背景色 | |
57 | + } | |
58 | + } | |
59 | + } | |
60 | + | |
61 | + /** | |
62 | + * 设置状态栏全透明 | |
63 | + * | |
64 | + * @param activity 需要设置的activity | |
65 | + */ | |
66 | + public static void setTransparent(Activity activity) { | |
67 | + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { | |
68 | + return; | |
69 | + } | |
70 | + setColor(activity, Color.TRANSPARENT); | |
71 | + } | |
72 | + | |
73 | + /** | |
74 | + * 修正 Toolbar 的位置 | |
75 | + * 在 Android 4.4 版本下无法显示内容在 StatusBar 下,所以无需修正 Toolbar 的位置 | |
76 | + * | |
77 | + * @param toolbar | |
78 | + */ | |
79 | + public static void fixToolbar(Toolbar toolbar, Activity activity) { | |
80 | + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { | |
81 | + int statusHeight = getStatusBarHeight(activity); | |
82 | + ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) toolbar.getLayoutParams(); | |
83 | + layoutParams.setMargins(0, statusHeight, 0, 0); | |
84 | + } | |
85 | + } | |
86 | + | |
87 | + /** | |
88 | + * 获取系统状态栏高度 | |
89 | + * | |
90 | + * @param context | |
91 | + * @return | |
92 | + */ | |
93 | + public static int getStatusBarHeight(Context context) { | |
94 | + Class<?> c = null; | |
95 | + Object obj = null; | |
96 | + Field field = null; | |
97 | + int x = 0, statusBarHeight = 0; | |
98 | + try { | |
99 | + c = Class.forName("com.android.internal.R$dimen"); | |
100 | + obj = c.newInstance(); | |
101 | + field = c.getField("status_bar_height"); | |
102 | + x = Integer.parseInt(field.get(obj).toString()); | |
103 | + statusBarHeight = context.getResources().getDimensionPixelSize(x); | |
104 | + } catch (Exception e1) { | |
105 | + e1.printStackTrace(); | |
106 | + } | |
107 | + return statusBarHeight; | |
108 | + } | |
109 | + | |
110 | +// /** | |
111 | +// * 获取状态栏高度 | |
112 | +// * | |
113 | +// * @param context context | |
114 | +// * @return 状态栏高度 | |
115 | +// */ | |
116 | +// private static int getStatusBarHeight(Context context) { | |
117 | +// // 获得状态栏高度 | |
118 | +// int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", | |
119 | +// "android"); | |
120 | +// return context.getResources().getDimensionPixelSize(resourceId); | |
121 | +// } | |
122 | + | |
123 | + /** | |
124 | + * 计算状态栏颜色 | |
125 | + * | |
126 | + * @param color color值 | |
127 | + * @param alpha alpha值 | |
128 | + * @return 最终的状态栏颜色 | |
129 | + */ | |
130 | + private static int calculateStatusColor(@ColorInt int color, int alpha) { | |
131 | + float a = 1 - alpha / 255f; | |
132 | + int red = color >> 16 & 0xff; | |
133 | + int green = color >> 8 & 0xff; | |
134 | + int blue = color & 0xff; | |
135 | + red = (int) (red * a + 0.5); | |
136 | + green = (int) (green * a + 0.5); | |
137 | + blue = (int) (blue * a + 0.5); | |
138 | + return 0xff << 24 | red << 16 | green << 8 | blue; | |
139 | + } | |
140 | +} | ... | ... |
... | ... | @@ -0,0 +1,57 @@ |
1 | +package com.shunzhi.mychartlibrary.utils; | |
2 | + | |
3 | +import java.util.concurrent.ArrayBlockingQueue; | |
4 | +import java.util.concurrent.BlockingQueue; | |
5 | +import java.util.concurrent.FutureTask; | |
6 | +import java.util.concurrent.ThreadFactory; | |
7 | +import java.util.concurrent.ThreadPoolExecutor; | |
8 | +import java.util.concurrent.TimeUnit; | |
9 | +import java.util.concurrent.atomic.AtomicInteger; | |
10 | + | |
11 | +/** | |
12 | + * Created by Mao Jiqing on 2016/11/7. | |
13 | + */ | |
14 | + | |
15 | +public class ThreadPoolUtils { | |
16 | + //线程池核心线程数 | |
17 | + private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); | |
18 | + private static int CORE_POOL_SIZE = CPU_COUNT + 1; | |
19 | + //线程池最大线程数 | |
20 | + private static int MAX_POOL_SIZE = CPU_COUNT * 2 + 1; | |
21 | + //额外线程空状态生存时间 | |
22 | + private static int KEEP_ALIVE_TIME = 10000; | |
23 | + //阻塞队列。当核心线程都被占用,且阻塞队列已满的情况下,才会开启额外线程。 | |
24 | + private static BlockingQueue workQueue = new ArrayBlockingQueue(10); | |
25 | + //线程池 | |
26 | + private static ThreadPoolExecutor threadPool; | |
27 | + | |
28 | + private ThreadPoolUtils() { | |
29 | + } | |
30 | + | |
31 | + //线程工厂 | |
32 | + private static ThreadFactory threadFactory = new ThreadFactory() { | |
33 | + private final AtomicInteger integer = new AtomicInteger(); | |
34 | + | |
35 | + @Override | |
36 | + public Thread newThread(Runnable r) { | |
37 | + return new Thread(r, "myThreadPool thread:" + integer.getAndIncrement()); | |
38 | + } | |
39 | + }; | |
40 | + | |
41 | + static { | |
42 | + threadPool = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME, | |
43 | + TimeUnit.SECONDS, workQueue, threadFactory); | |
44 | + } | |
45 | + | |
46 | + public static void execute(Runnable runnable) { | |
47 | + threadPool.execute(runnable); | |
48 | + } | |
49 | + | |
50 | + public static void execute(FutureTask futureTask) { | |
51 | + threadPool.execute(futureTask); | |
52 | + } | |
53 | + | |
54 | + public static void cancel(FutureTask futureTask) { | |
55 | + futureTask.cancel(true); | |
56 | + } | |
57 | +} | ... | ... |
... | ... | @@ -0,0 +1,336 @@ |
1 | +package com.shunzhi.mychartlibrary.widget; | |
2 | + | |
3 | +import android.annotation.SuppressLint; | |
4 | +import android.content.Context; | |
5 | +import android.os.Handler; | |
6 | +import android.os.Message; | |
7 | +import android.util.AttributeSet; | |
8 | +import android.view.MotionEvent; | |
9 | +import android.view.View; | |
10 | +import android.widget.Button; | |
11 | +import android.widget.Toast; | |
12 | + | |
13 | + | |
14 | +import com.shunzhi.mychartlibrary.R; | |
15 | +import com.shunzhi.mychartlibrary.utils.AudioManager; | |
16 | +import com.shunzhi.mychartlibrary.utils.FileSaveUtil; | |
17 | + | |
18 | +import java.io.File; | |
19 | +import java.io.IOException; | |
20 | +import java.math.BigDecimal; | |
21 | + | |
22 | +public class AudioRecordButton extends Button implements AudioManager.AudioStageListener { | |
23 | + private static final int STATE_NORMAL = 1; | |
24 | + private static final int STATE_RECORDING = 2; | |
25 | + private static final int STATE_WANT_TO_CANCEL = 3; | |
26 | + private static final int DISTANCE_Y_CANCEL = 50; | |
27 | + private static final int OVERTIME = 60; | |
28 | + private int mCurrentState = STATE_NORMAL; | |
29 | + // 已经开始录音 | |
30 | + private boolean isRecording = false; | |
31 | + private DialogManager mDialogManager; | |
32 | + private float mTime = 0; | |
33 | + // 是否触发了onlongclick,准备好了 | |
34 | + private boolean mReady; | |
35 | + private AudioManager mAudioManager; | |
36 | + private String saveDir = FileSaveUtil.voice_dir; | |
37 | + | |
38 | + private Handler mp3handler = new Handler() { | |
39 | + | |
40 | + @Override | |
41 | + public void handleMessage(Message msg) { | |
42 | + // TODO Auto-generated method stub | |
43 | + switch (msg.what) { | |
44 | + case AudioManager.MSG_ERROR_AUDIO_RECORD: | |
45 | + Toast.makeText(getContext(), "录音权限被屏蔽或者录音设备损坏!\n请在设置中检查是否开启权限!", | |
46 | + Toast.LENGTH_SHORT).show(); | |
47 | + mDialogManager.dimissDialog(); | |
48 | + mAudioManager.cancel(); | |
49 | + reset(); | |
50 | + break; | |
51 | + default: | |
52 | + break; | |
53 | + } | |
54 | + } | |
55 | + | |
56 | + }; | |
57 | + | |
58 | + /** | |
59 | + * 先实现两个参数的构造方法,布局会默认引用这个构造方法, 用一个 构造参数的构造方法来引用这个方法 * @param context | |
60 | + */ | |
61 | + | |
62 | + public AudioRecordButton(Context context) { | |
63 | + this(context, null); | |
64 | + // TODO Auto-generated constructor stub | |
65 | + } | |
66 | + | |
67 | + public AudioRecordButton(Context context, AttributeSet attrs) { | |
68 | + super(context, attrs); | |
69 | + | |
70 | + mDialogManager = new DialogManager(getContext()); | |
71 | + | |
72 | + try { | |
73 | + FileSaveUtil.createSDDirectory(FileSaveUtil.voice_dir); | |
74 | + } catch (IOException e) { | |
75 | + // TODO Auto-generated catch block | |
76 | + e.printStackTrace(); | |
77 | + } | |
78 | + mAudioManager = AudioManager.getInstance(FileSaveUtil.voice_dir); | |
79 | + mAudioManager.setOnAudioStageListener(this); | |
80 | + mAudioManager.setHandle(mp3handler); | |
81 | + setOnLongClickListener(new OnLongClickListener() { | |
82 | + | |
83 | + @Override | |
84 | + public boolean onLongClick(View v) { | |
85 | + // TODO Auto-generated method | |
86 | + try { | |
87 | + FileSaveUtil.createSDDirectory(saveDir); | |
88 | + } catch (IOException e) { | |
89 | + // TODO Auto-generated catch block | |
90 | + e.printStackTrace(); | |
91 | + } | |
92 | + mAudioManager.setVocDir(saveDir); | |
93 | + mListener.onStart(); | |
94 | + mReady = true; | |
95 | + mAudioManager.prepareAudio(); | |
96 | + return false; | |
97 | + } | |
98 | + }); | |
99 | + // TODO Auto-generated constructor stub | |
100 | + } | |
101 | + | |
102 | + public void setSaveDir(String saveDir) { | |
103 | + this.saveDir = saveDir + saveDir; | |
104 | + } | |
105 | + | |
106 | + /** | |
107 | + * 录音完成后的回调,回调给activiy,可以获得mtime和文件的路径 | |
108 | + */ | |
109 | + public interface AudioFinishRecorderListener { | |
110 | + void onStart(); | |
111 | + | |
112 | + void onFinished(float seconds, String filePath); | |
113 | + } | |
114 | + | |
115 | + private AudioFinishRecorderListener mListener; | |
116 | + | |
117 | + public void setAudioFinishRecorderListener( | |
118 | + AudioFinishRecorderListener listener) { | |
119 | + mListener = listener; | |
120 | + } | |
121 | + | |
122 | + // 获取音量大小的runnable | |
123 | + private Runnable mGetVoiceLevelRunnable = new Runnable() { | |
124 | + | |
125 | + @Override | |
126 | + public void run() { | |
127 | + // TODO Auto-generated method stub | |
128 | + while (isRecording) { | |
129 | + try { | |
130 | + Thread.sleep(100); | |
131 | + mTime += 0.1f; | |
132 | + mhandler.sendEmptyMessage(MSG_VOICE_CHANGE); | |
133 | + if (mTime >= OVERTIME) { | |
134 | + mTime = 60; | |
135 | + mhandler.sendEmptyMessage(MSG_OVERTIME_SEND); | |
136 | + isRecording = false; | |
137 | + break; | |
138 | + } | |
139 | + } catch (InterruptedException e) { | |
140 | + // TODO Auto-generated catch block | |
141 | + e.printStackTrace(); | |
142 | + } | |
143 | + } | |
144 | + } | |
145 | + }; | |
146 | + | |
147 | + // 准备三个常量 | |
148 | + private static final int MSG_AUDIO_PREPARED = 0X110; | |
149 | + private static final int MSG_VOICE_CHANGE = 0X111; | |
150 | + private static final int MSG_DIALOG_DIMISS = 0X112; | |
151 | + private static final int MSG_OVERTIME_SEND = 0X113; | |
152 | + | |
153 | + private Handler mhandler = new Handler() { | |
154 | + public void handleMessage(Message msg) { | |
155 | + switch (msg.what) { | |
156 | + case MSG_AUDIO_PREPARED: | |
157 | + // 显示应该是在audio end prepare之后回调 | |
158 | + if (isTouch) { | |
159 | + mTime = 0; | |
160 | + mDialogManager.showRecordingDialog(); | |
161 | + isRecording = true; | |
162 | + new Thread(mGetVoiceLevelRunnable).start(); | |
163 | + } | |
164 | + // 需要开启一个线程来变换音量 | |
165 | + break; | |
166 | + case MSG_VOICE_CHANGE: | |
167 | + mDialogManager.updateVoiceLevel(mAudioManager.getVoiceLevel(3)); | |
168 | + break; | |
169 | + case MSG_DIALOG_DIMISS: | |
170 | + isRecording = false; | |
171 | + mDialogManager.dimissDialog(); | |
172 | + break; | |
173 | + case MSG_OVERTIME_SEND: | |
174 | + mDialogManager.tooLong(); | |
175 | + mhandler.sendEmptyMessageDelayed(MSG_DIALOG_DIMISS, 1300);// 持续1.3s | |
176 | + if (mListener != null) {// 并且callbackActivity,保存录音 | |
177 | + File file = new File(mAudioManager.getCurrentFilePath()); | |
178 | + if (FileSaveUtil.isFileExists(file)) { | |
179 | + mListener.onFinished(mTime, | |
180 | + mAudioManager.getCurrentFilePath()); | |
181 | + }else{ | |
182 | + mp3handler.sendEmptyMessage(AudioManager.MSG_ERROR_AUDIO_RECORD); | |
183 | + } | |
184 | + } | |
185 | + isRecording = false; | |
186 | + reset();// 恢复标志位 | |
187 | + break; | |
188 | + } | |
189 | + }; | |
190 | + }; | |
191 | + | |
192 | + // 在这里面发送一个handler的消息 | |
193 | + @Override | |
194 | + public void wellPrepared() { | |
195 | + // TODO Auto-generated method stub | |
196 | + mhandler.sendEmptyMessage(MSG_AUDIO_PREPARED); | |
197 | + } | |
198 | + | |
199 | + /** | |
200 | + * 直接复写这个监听函数 | |
201 | + */ | |
202 | + private boolean isTouch = false; | |
203 | + | |
204 | + @SuppressLint("ClickableViewAccessibility") | |
205 | + @Override | |
206 | + public boolean onTouchEvent(MotionEvent event) { | |
207 | + // TODO Auto-generated method stub | |
208 | + int action = event.getAction(); | |
209 | + int x = (int) event.getX(); | |
210 | + int y = (int) event.getY(); | |
211 | + | |
212 | + switch (action) { | |
213 | + case MotionEvent.ACTION_DOWN: | |
214 | + isTouch = true; | |
215 | + changeState(STATE_RECORDING); | |
216 | + break; | |
217 | + case MotionEvent.ACTION_MOVE: | |
218 | + | |
219 | + if (isRecording) { | |
220 | + | |
221 | + // 根据x,y来判断用户是否想要取消 | |
222 | + if (wantToCancel(x, y)) { | |
223 | + changeState(STATE_WANT_TO_CANCEL); | |
224 | + } else { | |
225 | + changeState(STATE_RECORDING); | |
226 | + } | |
227 | + | |
228 | + } | |
229 | + | |
230 | + break; | |
231 | + case MotionEvent.ACTION_UP: | |
232 | + // 首先判断是否有触发onlongclick事件,没有的话直接返回reset | |
233 | + isTouch = false; | |
234 | + if (!mReady) { | |
235 | + reset(); | |
236 | + return super.onTouchEvent(event); | |
237 | + } | |
238 | + // 如果按的时间太短,还没准备好或者时间录制太短,就离开了,则显示这个dialog | |
239 | + if (!isRecording || mTime < 0.6f) { | |
240 | + mDialogManager.tooShort(); | |
241 | + mAudioManager.cancel(); | |
242 | + mhandler.sendEmptyMessageDelayed(MSG_DIALOG_DIMISS, 1300);// 持续1.3s | |
243 | + } else if (mCurrentState == STATE_RECORDING) {// 正常录制结束 | |
244 | + mDialogManager.dimissDialog(); | |
245 | + mAudioManager.release();// release释放一个mediarecorder | |
246 | + if (mListener != null) {// 并且callbackActivity,保存录音 | |
247 | + BigDecimal b = new BigDecimal(mTime); | |
248 | + float f1 = b.setScale(1, BigDecimal.ROUND_HALF_UP) | |
249 | + .floatValue(); | |
250 | + File file = new File(mAudioManager.getCurrentFilePath()); | |
251 | + if (FileSaveUtil.isFileExists(file)) { | |
252 | + mListener.onFinished(f1,mAudioManager.getCurrentFilePath()); | |
253 | + }else{ | |
254 | + mp3handler.sendEmptyMessage(AudioManager.MSG_ERROR_AUDIO_RECORD); | |
255 | + } | |
256 | + } | |
257 | + } else if (mCurrentState == STATE_WANT_TO_CANCEL) { | |
258 | + mAudioManager.cancel(); | |
259 | + mDialogManager.dimissDialog(); | |
260 | + } | |
261 | + isRecording = false; | |
262 | + reset();// 恢复标志位 | |
263 | + | |
264 | + break; | |
265 | + case MotionEvent.ACTION_CANCEL: | |
266 | + isTouch = false; | |
267 | + reset(); | |
268 | + break; | |
269 | + | |
270 | + } | |
271 | + | |
272 | + return super.onTouchEvent(event); | |
273 | + } | |
274 | + | |
275 | + /** | |
276 | + * 回复标志位以及状态 | |
277 | + */ | |
278 | + private void reset() { | |
279 | + // TODO Auto-generated method stub | |
280 | + isRecording = false; | |
281 | + changeState(STATE_NORMAL); | |
282 | + mReady = false; | |
283 | + mTime = 0; | |
284 | + } | |
285 | + | |
286 | + private boolean wantToCancel(int x, int y) { | |
287 | + // TODO Auto-generated method stub | |
288 | + | |
289 | + if (x < 0 || x > getWidth()) {// 判断是否在左边,右边,上边,下边 | |
290 | + return true; | |
291 | + } | |
292 | + if (y < -DISTANCE_Y_CANCEL || y > getHeight() + DISTANCE_Y_CANCEL) { | |
293 | + return true; | |
294 | + } | |
295 | + | |
296 | + return false; | |
297 | + } | |
298 | + | |
299 | + private void changeState(int state) { | |
300 | + // TODO Auto-generated method stub | |
301 | + if (mCurrentState != state) { | |
302 | + mCurrentState = state; | |
303 | + switch (mCurrentState) { | |
304 | + case STATE_NORMAL: | |
305 | + setBackgroundResource(R.drawable.button_recordnormal); | |
306 | + setText(R.string.normal); | |
307 | + | |
308 | + break; | |
309 | + case STATE_RECORDING: | |
310 | + setBackgroundResource(R.drawable.button_recording); | |
311 | + setText(R.string.recording); | |
312 | + if (isRecording) { | |
313 | + mDialogManager.recording(); | |
314 | + // 复写dialog.recording(); | |
315 | + } | |
316 | + break; | |
317 | + | |
318 | + case STATE_WANT_TO_CANCEL: | |
319 | + setBackgroundResource(R.drawable.button_recording); | |
320 | + setText(R.string.want_to_cancle); | |
321 | + // dialog want to cancel | |
322 | + mDialogManager.wantToCancel(); | |
323 | + break; | |
324 | + | |
325 | + } | |
326 | + } | |
327 | + | |
328 | + } | |
329 | + | |
330 | + @Override | |
331 | + public boolean onPreDraw() { | |
332 | + // TODO Auto-generated method stub | |
333 | + return false; | |
334 | + } | |
335 | + | |
336 | +} | ... | ... |
... | ... | @@ -0,0 +1,139 @@ |
1 | +package com.shunzhi.mychartlibrary.widget; | |
2 | + | |
3 | +import android.annotation.SuppressLint; | |
4 | +import android.content.Context; | |
5 | +import android.graphics.Bitmap; | |
6 | +import android.graphics.Bitmap.Config; | |
7 | +import android.graphics.BitmapFactory; | |
8 | +import android.graphics.Canvas; | |
9 | +import android.graphics.NinePatch; | |
10 | +import android.graphics.Paint; | |
11 | +import android.graphics.PorterDuff.Mode; | |
12 | +import android.graphics.PorterDuffXfermode; | |
13 | +import android.graphics.Rect; | |
14 | +import android.os.Handler; | |
15 | +import android.util.AttributeSet; | |
16 | +import android.view.Display; | |
17 | +import android.view.WindowManager; | |
18 | +import android.widget.ImageView; | |
19 | + | |
20 | +import com.bumptech.glide.Glide; | |
21 | +import com.bumptech.glide.request.animation.GlideAnimation; | |
22 | +import com.bumptech.glide.request.target.SimpleTarget; | |
23 | + | |
24 | + | |
25 | +public class BubbleImageView extends ImageView { | |
26 | + private Context context; | |
27 | + private Bitmap iconBitmap; | |
28 | + private int res; | |
29 | + private static final int OK_INT = 0x0001; | |
30 | + private static final int ERROR_INT = 0x0000; | |
31 | + @SuppressLint("HandlerLeak") | |
32 | + private Handler bitmapHandler = new Handler() { | |
33 | + public void handleMessage(android.os.Message msg) { | |
34 | + switch (msg.what) { | |
35 | + case OK_INT: | |
36 | + Bitmap bitmap_bg = BitmapFactory.decodeResource(getResources(), | |
37 | + res); | |
38 | + final Bitmap bp = getRoundCornerImage(bitmap_bg, iconBitmap); | |
39 | + setImageBitmap(bp); | |
40 | + break; | |
41 | + case ERROR_INT: | |
42 | + break; | |
43 | + } | |
44 | + }; | |
45 | + }; | |
46 | + | |
47 | + public BubbleImageView(Context context) { | |
48 | + super(context); | |
49 | + this.context = context; | |
50 | + } | |
51 | + | |
52 | + public BubbleImageView(Context context, AttributeSet attrs) { | |
53 | + super(context, attrs); | |
54 | + this.context = context; | |
55 | + } | |
56 | + | |
57 | + public BubbleImageView(Context context, AttributeSet attrs, int defStyle) { | |
58 | + super(context, attrs, defStyle); | |
59 | + this.context = context; | |
60 | + } | |
61 | + | |
62 | + public void load(String url, int res, int placeHolderPic) { | |
63 | + this.setImageResource(placeHolderPic); | |
64 | + this.res = res; | |
65 | + Glide.with(context).load(url).asBitmap().into(new SimpleTarget<Bitmap>() { | |
66 | + @Override | |
67 | + public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) { | |
68 | + if (resource != null) { | |
69 | + iconBitmap = resource; | |
70 | + bitmapHandler.sendEmptyMessage(OK_INT); | |
71 | + } | |
72 | + } | |
73 | + }); | |
74 | + } | |
75 | + | |
76 | + public void setLocalImageBitmap(Bitmap bm, int res) { | |
77 | + // TODO Auto-generated method stub | |
78 | + Bitmap bitmap_bg = BitmapFactory.decodeResource(getResources(), res); | |
79 | + final Bitmap bp = getRoundCornerImage(bitmap_bg, bm); | |
80 | + setImageBitmap(bp); | |
81 | + } | |
82 | + | |
83 | + public Bitmap getRoundCornerImage(Bitmap bitmap_bg, Bitmap bitmap_in) { | |
84 | + int width = bitmap_in.getWidth(); | |
85 | + int height = bitmap_in.getHeight(); | |
86 | + if(height != 0){ | |
87 | + double scale = (width * 1.00) / height; | |
88 | + if (width >= height) { | |
89 | + width = getBitmapWidth(); | |
90 | + height = (int) (width / scale); | |
91 | + } else { | |
92 | + height = getBitmapHeight(); | |
93 | + width = (int) (height * scale); | |
94 | + } | |
95 | + }else{ | |
96 | + width = 100; | |
97 | + height = 100; | |
98 | + } | |
99 | + Bitmap roundConcerImage = Bitmap.createBitmap(width, height, | |
100 | + Config.ARGB_8888); | |
101 | + Canvas canvas = new Canvas(roundConcerImage); | |
102 | + Paint paint = new Paint(); | |
103 | + Rect rect = new Rect(0, 0, width, height); | |
104 | + Rect rectF = new Rect(0, 0, bitmap_in.getWidth(), bitmap_in.getHeight()); | |
105 | + paint.setAntiAlias(true); | |
106 | + NinePatch patch = new NinePatch(bitmap_bg, | |
107 | + bitmap_bg.getNinePatchChunk(), null); | |
108 | + patch.draw(canvas, rect); | |
109 | + paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); | |
110 | + canvas.drawBitmap(bitmap_in, rectF, rect, paint); | |
111 | + return roundConcerImage; | |
112 | + } | |
113 | + | |
114 | + // 获取屏幕的宽度 | |
115 | + @SuppressWarnings("deprecation") | |
116 | + public int getScreenWidth(Context context) { | |
117 | + WindowManager manager = (WindowManager) context | |
118 | + .getSystemService(Context.WINDOW_SERVICE); | |
119 | + Display display = manager.getDefaultDisplay(); | |
120 | + return display.getWidth(); | |
121 | + } | |
122 | + | |
123 | + // 获取屏幕的高度 | |
124 | + @SuppressWarnings("deprecation") | |
125 | + public int getScreenHeight(Context context) { | |
126 | + WindowManager manager = (WindowManager) context | |
127 | + .getSystemService(Context.WINDOW_SERVICE); | |
128 | + Display display = manager.getDefaultDisplay(); | |
129 | + return display.getHeight(); | |
130 | + } | |
131 | + | |
132 | + public int getBitmapWidth() { | |
133 | + return getScreenWidth(context) / 3; | |
134 | + } | |
135 | + | |
136 | + public int getBitmapHeight() { | |
137 | + return getScreenHeight(context) / 4; | |
138 | + } | |
139 | +} | ... | ... |
... | ... | @@ -0,0 +1,70 @@ |
1 | +package com.shunzhi.mychartlibrary.widget; | |
2 | + | |
3 | +import android.content.Context; | |
4 | +import android.util.AttributeSet; | |
5 | +import android.view.LayoutInflater; | |
6 | +import android.view.View; | |
7 | +import android.widget.LinearLayout; | |
8 | + | |
9 | +import com.shunzhi.mychartlibrary.R; | |
10 | + | |
11 | +public class ChatBottomView extends LinearLayout{ | |
12 | + private View baseView; | |
13 | + private LinearLayout imageGroup; | |
14 | + private LinearLayout cameraGroup; | |
15 | + private LinearLayout phraseGroup; | |
16 | + private HeadIconSelectorView.OnHeadIconClickListener onHeadIconClickListener; | |
17 | + public static final int FROM_CAMERA = 1; | |
18 | + public static final int FROM_GALLERY = 2; | |
19 | + public static final int FROM_PHRASE = 3; | |
20 | + public ChatBottomView(Context context, AttributeSet attrs) { | |
21 | + super(context, attrs); | |
22 | + // TODO Auto-generated constructor stub | |
23 | + findView(); | |
24 | + init(); | |
25 | + } | |
26 | + | |
27 | + private void findView(){ | |
28 | + baseView = LayoutInflater.from(getContext()).inflate(R.layout.layout_tongbaobottom, this); | |
29 | + imageGroup = (LinearLayout) baseView.findViewById(R.id.image_bottom_group); | |
30 | + cameraGroup = (LinearLayout) baseView.findViewById(R.id.camera_group); | |
31 | + phraseGroup = (LinearLayout) baseView.findViewById(R.id.phrase_group); | |
32 | + } | |
33 | + private void init(){ | |
34 | + cameraGroup.setOnClickListener(new OnClickListener() { | |
35 | + | |
36 | + @Override | |
37 | + public void onClick(View v) { | |
38 | + if (null != onHeadIconClickListener) { | |
39 | + onHeadIconClickListener.onClick(FROM_CAMERA); | |
40 | + } | |
41 | + } | |
42 | + }); | |
43 | + imageGroup.setOnClickListener(new OnClickListener() { | |
44 | + | |
45 | + @Override | |
46 | + public void onClick(View v) { | |
47 | + | |
48 | + if (null != onHeadIconClickListener) { | |
49 | + onHeadIconClickListener.onClick(FROM_GALLERY); | |
50 | + } | |
51 | + } | |
52 | + }); | |
53 | + phraseGroup.setOnClickListener(new OnClickListener() { | |
54 | + | |
55 | + @Override | |
56 | + public void onClick(View v) { | |
57 | + | |
58 | + if (null != onHeadIconClickListener) { | |
59 | + onHeadIconClickListener.onClick(FROM_PHRASE); | |
60 | + } | |
61 | + } | |
62 | + }); | |
63 | + } | |
64 | + | |
65 | + public void setOnHeadIconClickListener( | |
66 | + HeadIconSelectorView.OnHeadIconClickListener onHeadIconClickListener) { | |
67 | + // TODO Auto-generated method stub | |
68 | + this.onHeadIconClickListener = onHeadIconClickListener; | |
69 | + } | |
70 | +} | ... | ... |
... | ... | @@ -0,0 +1,109 @@ |
1 | +package com.shunzhi.mychartlibrary.widget; | |
2 | + | |
3 | +import android.content.Context; | |
4 | +import android.graphics.Bitmap; | |
5 | +import android.graphics.Canvas; | |
6 | +import android.graphics.Paint; | |
7 | +import android.graphics.PorterDuff; | |
8 | +import android.graphics.PorterDuffXfermode; | |
9 | +import android.graphics.drawable.Drawable; | |
10 | +import android.support.v4.content.ContextCompat; | |
11 | +import android.view.Display; | |
12 | +import android.view.WindowManager; | |
13 | + | |
14 | +import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; | |
15 | +import com.bumptech.glide.load.resource.bitmap.BitmapTransformation; | |
16 | +import com.bumptech.glide.load.resource.bitmap.TransformationUtils; | |
17 | + | |
18 | +/** | |
19 | + * Created by Mao Jiqing on 2016/11/4. | |
20 | + */ | |
21 | + | |
22 | +public class CustomShapeTransformation extends BitmapTransformation { | |
23 | + | |
24 | + private Paint mPaint; // 画笔 | |
25 | + private Context mContext; | |
26 | + private int mShapeRes; // 形状的drawable资源 | |
27 | + | |
28 | + public CustomShapeTransformation(Context context, int shapeRes) { | |
29 | + super(context); | |
30 | + mContext = context; | |
31 | + mShapeRes = shapeRes; | |
32 | + // 实例化Paint对象,并设置Xfermode为SRC_IN | |
33 | + mPaint = new Paint(); | |
34 | + mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); | |
35 | + } | |
36 | + | |
37 | + @Override | |
38 | + // 复写该方法,完成图片的转换 | |
39 | + public Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) { | |
40 | + // 获取到形状资源的Drawable对象 | |
41 | + Drawable shape = ContextCompat.getDrawable(mContext, mShapeRes); | |
42 | + int width = toTransform.getWidth(); | |
43 | + int height = toTransform.getHeight(); | |
44 | + if(height != 0){ | |
45 | + double scale = (width * 1.00) / height; | |
46 | + if (width >= height) { | |
47 | + width = getBitmapWidth(); | |
48 | + height = (int) (width / scale); | |
49 | + } else { | |
50 | + height = getBitmapHeight(); | |
51 | + width = (int) (height * scale); | |
52 | + } | |
53 | + }else{ | |
54 | + width = 100; | |
55 | + height = 100; | |
56 | + } | |
57 | + // 居中裁剪图片,调用Glide库中TransformationUtils类的centerCrop()方法完成裁剪,保证图片居中且填满 | |
58 | + final Bitmap toReuse = pool.get(width, height, toTransform.getConfig() != null | |
59 | + ? toTransform.getConfig() : Bitmap.Config.ARGB_8888); | |
60 | + Bitmap transformed = TransformationUtils.centerCrop(toReuse, toTransform, width, height); | |
61 | + if (toReuse != null && toReuse != transformed && !pool.put(toReuse)) { | |
62 | + toReuse.recycle(); | |
63 | + } | |
64 | + | |
65 | + // 根据算出的宽高新建Bitmap对象并设置到画布上 | |
66 | + Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); | |
67 | + Canvas canvas = new Canvas(bitmap); | |
68 | + // 设置形状的大小与图片的大小一致 | |
69 | + shape.setBounds(0, 0, width, height); | |
70 | + // 将图片画到画布上 | |
71 | + shape.draw(canvas); | |
72 | + // 将裁剪后的图片画得画布上 | |
73 | + canvas.drawBitmap(transformed, 0, 0, mPaint); | |
74 | + | |
75 | + return bitmap; | |
76 | + } | |
77 | + | |
78 | + @Override | |
79 | + public String getId() { | |
80 | + // 用于缓存的唯一标识符 | |
81 | + return "CustomShapeTransformation" + mShapeRes; | |
82 | + } | |
83 | + | |
84 | + // 获取屏幕的宽度 | |
85 | + @SuppressWarnings("deprecation") | |
86 | + public int getScreenWidth(Context context) { | |
87 | + WindowManager manager = (WindowManager) context | |
88 | + .getSystemService(Context.WINDOW_SERVICE); | |
89 | + Display display = manager.getDefaultDisplay(); | |
90 | + return display.getWidth(); | |
91 | + } | |
92 | + | |
93 | + // 获取屏幕的高度 | |
94 | + @SuppressWarnings("deprecation") | |
95 | + public int getScreenHeight(Context context) { | |
96 | + WindowManager manager = (WindowManager) context | |
97 | + .getSystemService(Context.WINDOW_SERVICE); | |
98 | + Display display = manager.getDefaultDisplay(); | |
99 | + return display.getHeight(); | |
100 | + } | |
101 | + | |
102 | + public int getBitmapWidth() { | |
103 | + return getScreenWidth(mContext) / 3; | |
104 | + } | |
105 | + | |
106 | + public int getBitmapHeight() { | |
107 | + return getScreenHeight(mContext) / 4; | |
108 | + } | |
109 | +} | |
0 | 110 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,148 @@ |
1 | +package com.shunzhi.mychartlibrary.widget; | |
2 | + | |
3 | +import android.annotation.SuppressLint; | |
4 | +import android.app.Dialog; | |
5 | +import android.content.Context; | |
6 | +import android.view.LayoutInflater; | |
7 | +import android.view.View; | |
8 | +import android.view.Window; | |
9 | +import android.view.WindowManager; | |
10 | +import android.widget.ImageView; | |
11 | +import android.widget.TextView; | |
12 | + | |
13 | +import com.shunzhi.mychartlibrary.R; | |
14 | +import com.shunzhi.mychartlibrary.utils.ScreenUtil; | |
15 | + | |
16 | +@SuppressLint("InflateParams") | |
17 | +public class DialogManager { | |
18 | + | |
19 | + /** | |
20 | + * 以下为dialog的初始化控件,包括其中的布局文件 | |
21 | + */ | |
22 | + | |
23 | + private Dialog mDialog; | |
24 | + | |
25 | + private ImageView mIcon; | |
26 | + private ImageView mVoice; | |
27 | + | |
28 | + private TextView mLable; | |
29 | + | |
30 | + private Context mContext; | |
31 | + | |
32 | + public DialogManager(Context context) { | |
33 | + // TODO Auto-generated constructor stub | |
34 | + mContext = context; | |
35 | + } | |
36 | + | |
37 | + public void showRecordingDialog() { | |
38 | + // TODO Auto-generated method stub | |
39 | + | |
40 | + mDialog = new Dialog(mContext, R.style.Theme_audioDialog); | |
41 | + mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE); | |
42 | + | |
43 | + // 用layoutinflater来引用布局 | |
44 | + LayoutInflater inflater = LayoutInflater.from(mContext); | |
45 | + View view = inflater.inflate(R.layout.layout_voice_dialog_manager, null); | |
46 | + mDialog.setContentView(view); | |
47 | + | |
48 | + mIcon = (ImageView) mDialog.findViewById(R.id.dialog_icon); | |
49 | + mVoice = (ImageView) mDialog.findViewById(R.id.dialog_voice); | |
50 | + mLable = (TextView) mDialog.findViewById(R.id.recorder_dialogtext); | |
51 | + | |
52 | + Window dialogWindow = mDialog.getWindow(); | |
53 | + WindowManager.LayoutParams lp = dialogWindow.getAttributes(); | |
54 | + int width = ScreenUtil.getScreenWidth(mContext) / 2; | |
55 | + lp.width = width; // 宽度 | |
56 | + lp.height = width; // 高度 | |
57 | + dialogWindow.setAttributes(lp); | |
58 | + mDialog.setCancelable(false); | |
59 | + mDialog.show(); | |
60 | + | |
61 | + } | |
62 | + | |
63 | + /** | |
64 | + * 设置正在录音时的dialog界面 | |
65 | + */ | |
66 | + public void recording() { | |
67 | + if (mDialog != null && mDialog.isShowing()) { | |
68 | + mIcon.setVisibility(View.GONE); | |
69 | + mVoice.setVisibility(View.VISIBLE); | |
70 | + mLable.setVisibility(View.VISIBLE); | |
71 | + mLable.setText(R.string.shouzhishanghua); | |
72 | + } | |
73 | + } | |
74 | + | |
75 | + /** | |
76 | + * 取消界面 | |
77 | + */ | |
78 | + public void wantToCancel() { | |
79 | + // TODO Auto-generated method stub | |
80 | + if (mDialog != null && mDialog.isShowing()) { | |
81 | + mIcon.setVisibility(View.VISIBLE); | |
82 | + mVoice.setVisibility(View.GONE); | |
83 | + mLable.setVisibility(View.VISIBLE); | |
84 | + | |
85 | + mIcon.setImageResource(R.mipmap.cancel); | |
86 | + mLable.setText(R.string.want_to_cancle); | |
87 | + } | |
88 | + | |
89 | + } | |
90 | + | |
91 | + // 时间过短 | |
92 | + public void tooShort() { | |
93 | + // TODO Auto-generated method stub | |
94 | + if (mDialog != null && mDialog.isShowing()) { | |
95 | + mIcon.setVisibility(View.VISIBLE); | |
96 | + mVoice.setVisibility(View.GONE); | |
97 | + mLable.setVisibility(View.VISIBLE); | |
98 | + | |
99 | + mIcon.setImageResource(R.mipmap.voice_to_short); | |
100 | + mLable.setText(R.string.tooshort); | |
101 | + } | |
102 | + | |
103 | + } | |
104 | + // 时间过长 | |
105 | + public void tooLong() { | |
106 | + // TODO Auto-generated method stub | |
107 | + if (mDialog != null && mDialog.isShowing()) { | |
108 | + mIcon.setVisibility(View.VISIBLE); | |
109 | + mVoice.setVisibility(View.GONE); | |
110 | + mLable.setVisibility(View.VISIBLE); | |
111 | + | |
112 | + mIcon.setImageResource(R.mipmap.voice_to_short); | |
113 | + mLable.setText(R.string.toolong); | |
114 | + } | |
115 | + | |
116 | + } | |
117 | + // 隐藏dialog | |
118 | + public void dimissDialog() { | |
119 | + // TODO Auto-generated method stub | |
120 | + | |
121 | + if (mDialog != null && mDialog.isShowing()) { | |
122 | + mDialog.dismiss(); | |
123 | + mDialog = null; | |
124 | + } | |
125 | + | |
126 | + } | |
127 | + | |
128 | + public void updateVoiceLevel(int level) { | |
129 | + // TODO Auto-generated method stub | |
130 | + | |
131 | + if (mDialog != null && mDialog.isShowing()) { | |
132 | + int resId; | |
133 | + if(level >= 1 && level < 2){ | |
134 | + resId = mContext.getResources().getIdentifier("tb_voice1", | |
135 | + "mipmap", mContext.getPackageName()); | |
136 | + }else if(level >= 2 && level < 3){ | |
137 | + resId = mContext.getResources().getIdentifier("tb_voice2", | |
138 | + "mipmap", mContext.getPackageName()); | |
139 | + }else{ | |
140 | + resId = mContext.getResources().getIdentifier("tb_voice3", | |
141 | + "mipmap", mContext.getPackageName()); | |
142 | + } | |
143 | + mVoice.setImageResource(resId); | |
144 | + } | |
145 | + | |
146 | + } | |
147 | + | |
148 | +} | ... | ... |
... | ... | @@ -0,0 +1,38 @@ |
1 | +/** | |
2 | + * Copyright (C) 2013-2014 EaseMob Technologies. All rights reserved. | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
8 | + * Unless required by applicable law or agreed to in writing, software | |
9 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
10 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
11 | + * See the License for the specific language governing permissions and | |
12 | + * limitations under the License. | |
13 | + */ | |
14 | +package com.shunzhi.mychartlibrary.widget; | |
15 | + | |
16 | +import android.content.Context; | |
17 | +import android.util.AttributeSet; | |
18 | +import android.widget.GridView; | |
19 | + | |
20 | +public class ExpandGridView extends GridView { | |
21 | + | |
22 | + public ExpandGridView(Context context) { | |
23 | + super(context); | |
24 | + } | |
25 | + | |
26 | + public ExpandGridView(Context context, AttributeSet attrs) { | |
27 | + super(context, attrs); | |
28 | + } | |
29 | + | |
30 | + | |
31 | + @Override | |
32 | + public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | |
33 | + int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); | |
34 | + super.onMeasure(widthMeasureSpec, expandSpec); | |
35 | + } | |
36 | + | |
37 | + | |
38 | +} | ... | ... |
... | ... | @@ -0,0 +1,303 @@ |
1 | +package com.shunzhi.mychartlibrary.widget; | |
2 | + | |
3 | +import android.annotation.SuppressLint; | |
4 | +import android.content.Context; | |
5 | +import android.graphics.Bitmap; | |
6 | +import android.graphics.BitmapFactory; | |
7 | +import android.os.Handler; | |
8 | +import android.text.Spannable; | |
9 | +import android.text.SpannableString; | |
10 | +import android.text.style.ImageSpan; | |
11 | +import android.util.AttributeSet; | |
12 | +import android.widget.EditText; | |
13 | + | |
14 | + | |
15 | +import com.shunzhi.mychartlibrary.utils.FaceData; | |
16 | +import com.shunzhi.mychartlibrary.utils.GifOpenHelper; | |
17 | +import com.shunzhi.mychartlibrary.utils.ScreenUtil; | |
18 | + | |
19 | +import java.lang.ref.WeakReference; | |
20 | +import java.util.ArrayList; | |
21 | +import java.util.regex.Matcher; | |
22 | +import java.util.regex.Pattern; | |
23 | + | |
24 | +public class GifTextView extends EditText { | |
25 | + /** | |
26 | + * 注:如果获取的gif帧与帧之间的时间间隔都不相同,建议调个固定的,最好的方法是将gif图的间隔设置相同 | |
27 | + */ | |
28 | + private static final int DELAYED = 300; | |
29 | + | |
30 | + /** | |
31 | + * @author Dragon SpanInfo | |
32 | + * 类用于存储一个要显示的图片(动态或静态)的信息,包括分解后的每一帧mapList、替代文字的起始位置、终止位置 | |
33 | + * 、帧的总数、当前需要显示的帧、帧与帧之间的时间间隔 | |
34 | + */ | |
35 | + private class SpanInfo { | |
36 | + ArrayList<Bitmap> mapList; | |
37 | + @SuppressWarnings("unused") | |
38 | + int start, end, frameCount, currentFrameIndex, delay; | |
39 | + | |
40 | + public SpanInfo() { | |
41 | + mapList = new ArrayList<Bitmap>(); | |
42 | + start = end = frameCount = currentFrameIndex = delay = 0; | |
43 | + } | |
44 | + } | |
45 | + | |
46 | + /** | |
47 | + * spanInfoList 是一个SpanInfo的list ,用于处理一个TextView中出现多个要匹配的图片的情况 | |
48 | + */ | |
49 | + private ArrayList<SpanInfo> spanInfoList = null; | |
50 | + private Handler handler; // 用于处理从子线程TextView传来的消息 | |
51 | + private String myText; // 存储textView应该显示的文本 | |
52 | + | |
53 | + /** | |
54 | + * 这三个构造方法一个也不要少,否则会产生CastException,注意在这三个构造函数中都为spanInfoList实例化,可能有些浪费 | |
55 | + * ,但保证不会有空指针异常 | |
56 | + * | |
57 | + * @param context | |
58 | + * @param attrs | |
59 | + * @param defStyle | |
60 | + */ | |
61 | + @SuppressLint("NewApi") | |
62 | + public GifTextView(Context context, AttributeSet attrs, int defStyle) { | |
63 | + super(context, attrs, defStyle); | |
64 | + // TODO Auto-generated constructor stub | |
65 | + // spanInfoList = new ArrayList<SpanInfo>(); | |
66 | + GifTextView.this.setFocusableInTouchMode(false); | |
67 | + } | |
68 | + | |
69 | + @SuppressLint("NewApi") | |
70 | + public GifTextView(Context context, AttributeSet attrs) { | |
71 | + super(context, attrs); | |
72 | + // TODO Auto-generated constructor stub | |
73 | + // spanInfoList = new ArrayList<SpanInfo>(); | |
74 | + GifTextView.this.setFocusableInTouchMode(false); | |
75 | + } | |
76 | + | |
77 | + @SuppressLint("NewApi") | |
78 | + public GifTextView(Context context) { | |
79 | + super(context); | |
80 | + // TODO Auto-generated constructor stub | |
81 | + // spanInfoList = new ArrayList<SpanInfo>(); | |
82 | + GifTextView.this.setFocusableInTouchMode(false); | |
83 | + } | |
84 | + | |
85 | + /** | |
86 | + * 对要显示在textView上的文本进行解析,看看是否文本中有需要与Gif或者静态图片匹配的文本 若有,那么调用parseGif | |
87 | + * 对该文本对应的Gif图片进行解析 或者嗲用parseBmp解析静态图片 | |
88 | + * | |
89 | + * @param inputStr | |
90 | + */ | |
91 | + private boolean parseText(String inputStr) { | |
92 | + myText = inputStr; | |
93 | +// Pattern mPattern = Pattern.compile("\\[:..\\]|\\[:...\\]"); | |
94 | + Pattern mPattern = Pattern.compile("\\[[^\\]]+\\]"); | |
95 | + Matcher mMatcher = mPattern.matcher(inputStr); | |
96 | + boolean hasGif = false; | |
97 | + while (mMatcher.find()) { | |
98 | + String faceName = mMatcher.group(); | |
99 | + Integer faceId = null; | |
100 | + /** | |
101 | + * 这里匹配时用到了图片库,即一个专门存放图片id和其匹配的名称的静态对象,这两个静态对象放在了FaceData.java | |
102 | + * 中,并采用了静态块的方法进行了初始化,不会有空指针异常 | |
103 | + */ | |
104 | + if ((faceId = FaceData.gifFaceInfo.get(faceName)) != null) { | |
105 | + if (isGif) { | |
106 | + parseGif(faceId, mMatcher.start(), mMatcher.end()); | |
107 | + } else { | |
108 | + parseBmp(faceId, mMatcher.start(), mMatcher.end()); | |
109 | + } | |
110 | + } | |
111 | + hasGif = true; | |
112 | + } | |
113 | + return hasGif; | |
114 | + } | |
115 | + | |
116 | + /** | |
117 | + * 对静态图片进行解析: | |
118 | + * 创建一个SpanInfo对象,帧数设为1,按照下面的参数设置,最后不要忘记将SpanInfo对象添加进spanInfoList中, 否则不会显示 | |
119 | + * | |
120 | + * @param resourceId | |
121 | + * @param start | |
122 | + * @param end | |
123 | + */ | |
124 | + @SuppressWarnings("unused") | |
125 | + private void parseBmp(int resourceId, int start, int end) { | |
126 | + Bitmap bitmap = BitmapFactory.decodeResource(getContext() | |
127 | + .getResources(), resourceId); | |
128 | + ImageSpan imageSpan = new ImageSpan(getContext(), bitmap); | |
129 | + SpanInfo spanInfo = new SpanInfo(); | |
130 | + spanInfo.currentFrameIndex = 0; | |
131 | + spanInfo.frameCount = 1; | |
132 | + spanInfo.start = start; | |
133 | + spanInfo.end = end; | |
134 | + spanInfo.delay = 100; | |
135 | + spanInfo.mapList.add(bitmap); | |
136 | + spanInfoList.add(spanInfo); | |
137 | + | |
138 | + } | |
139 | + | |
140 | + /** | |
141 | + * 解析Gif图片,与静态图片唯一的不同是这里需要调用GifOpenHelper类读取Gif返回一系一组bitmap(用for 循环把这一 | |
142 | + * 组的bitmap存储在SpanInfo.mapList中,此时的frameCount参数也大于1了) | |
143 | + * | |
144 | + * @param resourceId | |
145 | + * @param start | |
146 | + * @param end | |
147 | + */ | |
148 | + private void parseGif(int resourceId, int start, int end) { | |
149 | + | |
150 | + GifOpenHelper helper = new GifOpenHelper(); | |
151 | + helper.read(getContext().getResources().openRawResource(resourceId)); | |
152 | + SpanInfo spanInfo = new SpanInfo(); | |
153 | + spanInfo.currentFrameIndex = 0; | |
154 | + spanInfo.frameCount = helper.getFrameCount(); | |
155 | + spanInfo.start = start; | |
156 | + spanInfo.end = end; | |
157 | + spanInfo.mapList.add(helper.getImage()); | |
158 | + for (int i = 1; i < helper.getFrameCount(); i++) { | |
159 | + spanInfo.mapList.add(helper.nextBitmap()); | |
160 | + } | |
161 | + spanInfo.delay = helper.nextDelay(); // 获得每一帧之间的延迟 | |
162 | + spanInfoList.add(spanInfo); | |
163 | + | |
164 | + } | |
165 | + | |
166 | + private boolean isGif; | |
167 | + | |
168 | + /** | |
169 | + * GifTextView 与外部对象的接口,以后设置文本内容时使用setSpanText() 而不再是setText(); | |
170 | + * | |
171 | + * @param handler | |
172 | + * @param text | |
173 | + */ | |
174 | + public void setSpanText(Handler handler, final String text, boolean isGif) { | |
175 | + this.handler = handler; // 获得UI的Handler | |
176 | + this.isGif = isGif; | |
177 | + spanInfoList = new ArrayList<SpanInfo>(); | |
178 | +// ThreadPoolUtils.execute(new Runnable() { | |
179 | +// | |
180 | +// @Override | |
181 | +// public void run() { | |
182 | +//// // TODO Auto-generated method stub | |
183 | + if (parseText(text)) {// 对String对象进行解析 | |
184 | +// mStartHandler.sendEmptyMessage(0); | |
185 | + if (parseMessage(this)) { | |
186 | + startPost(); | |
187 | + } | |
188 | + } else { | |
189 | +// mStartHandler.sendEmptyMessage(1); | |
190 | + setText(myText); | |
191 | + } | |
192 | +// } | |
193 | +// }); | |
194 | + } | |
195 | + | |
196 | +// private StartHandler mStartHandler = new StartHandler(this); | |
197 | +// | |
198 | +// public static class StartHandler extends Handler { | |
199 | +// private final WeakReference<GifTextView> mGifWeakReference; | |
200 | +// | |
201 | +// public StartHandler(GifTextView gifTextView) { | |
202 | +// mGifWeakReference = new WeakReference<GifTextView>(gifTextView); | |
203 | +// } | |
204 | +// | |
205 | +// @Override | |
206 | +// public void handleMessage(Message msg) { | |
207 | +// GifTextView gifTextView = mGifWeakReference.get(); | |
208 | +// if (gifTextView != null) { | |
209 | +// if (msg.what == 0) { | |
210 | +// gifTextView.startPost(); | |
211 | +// } else if (msg.what == 1) { | |
212 | +// gifTextView.setText(gifTextView.myText); | |
213 | +// } | |
214 | +// } | |
215 | +// } | |
216 | +// } | |
217 | + | |
218 | + public boolean parseMessage(GifTextView gifTextView) { | |
219 | + if (gifTextView.myText != null && !gifTextView.myText.equals("")) { | |
220 | + SpannableString sb = new SpannableString("" + gifTextView.myText); // 获得要显示的文本 | |
221 | + int gifCount = 0; | |
222 | + SpanInfo info = null; | |
223 | + for (int i = 0; i < gifTextView.spanInfoList.size(); i++) { // for循环,处理显示多个图片的问题 | |
224 | + info = gifTextView.spanInfoList.get(i); | |
225 | + if (info.mapList.size() > 1) { | |
226 | + /* | |
227 | + * gifCount用来区分是Gif还是BMP,若是gif gifCount>0 | |
228 | + * ,否则gifCount=0 | |
229 | + */ | |
230 | + gifCount++; | |
231 | + | |
232 | + } | |
233 | + Bitmap bitmap = info.mapList | |
234 | + .get(info.currentFrameIndex); | |
235 | + info.currentFrameIndex = (info.currentFrameIndex + 1) | |
236 | + % (info.frameCount); | |
237 | + /** | |
238 | + * currentFrameIndex | |
239 | + * 用于控制当前应该显示的帧的序号,每次显示之后currentFrameIndex 应该加1 | |
240 | + * ,加到frameCount后再变成0循环显示 | |
241 | + */ | |
242 | + int size = ScreenUtil.dip2px(gifTextView.getContext(), 30); | |
243 | + if (gifCount != 0) { | |
244 | + bitmap = Bitmap.createScaledBitmap(bitmap, size, | |
245 | + size, true); | |
246 | + | |
247 | + } else { | |
248 | + bitmap = Bitmap.createScaledBitmap(bitmap, size, | |
249 | + size, true); | |
250 | + } | |
251 | + ImageSpan imageSpan = new ImageSpan(gifTextView.getContext(), | |
252 | + bitmap); | |
253 | + if (info.end <= sb.length()) { | |
254 | + sb.setSpan(imageSpan, info.start, info.end, | |
255 | + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); | |
256 | + } else { | |
257 | + break; | |
258 | + } | |
259 | + | |
260 | + } | |
261 | + // 对所有的图片对应的ImageSpan完成设置后,调用TextView的setText方法设置文本 | |
262 | + gifTextView.setText(sb); | |
263 | + if (gifCount != 0) { | |
264 | + return true; | |
265 | + } else { | |
266 | + return false; | |
267 | + } | |
268 | + } | |
269 | + return false; | |
270 | + } | |
271 | + | |
272 | + public TextRunnable rTextRunnable; | |
273 | + | |
274 | + public void startPost() { | |
275 | + rTextRunnable = new TextRunnable(this); // 生成Runnable对象 | |
276 | + handler.post(rTextRunnable); // 利用UI线程的Handler 将r添加进消息队列中。 | |
277 | + } | |
278 | + | |
279 | + public static final class TextRunnable implements Runnable { | |
280 | + private final WeakReference<GifTextView> mWeakReference; | |
281 | + | |
282 | + public TextRunnable(GifTextView f) { | |
283 | + mWeakReference = new WeakReference<GifTextView>(f); | |
284 | + } | |
285 | + | |
286 | + @Override | |
287 | + public void run() { | |
288 | + // TODO Auto-generated method stub | |
289 | + GifTextView gifTextView = mWeakReference.get(); | |
290 | + if (gifTextView != null) { | |
291 | + /** | |
292 | + * 这一步是为了节省内存而是用,即如果文本中只有静态图片没有动态图片,那么该线程就此终止,不会重复执行 | |
293 | + * 。而如果有动图,那么会一直执行 | |
294 | + */ | |
295 | + if (gifTextView.parseMessage(gifTextView)) { | |
296 | + gifTextView.handler.postDelayed(this, DELAYED); | |
297 | + } | |
298 | + } | |
299 | + } | |
300 | + } | |
301 | + | |
302 | +} | |
303 | + | ... | ... |
... | ... | @@ -0,0 +1,331 @@ |
1 | +package com.shunzhi.mychartlibrary.widget; | |
2 | + | |
3 | +import android.annotation.SuppressLint; | |
4 | +import android.content.Context; | |
5 | +import android.view.GestureDetector; | |
6 | +import android.view.KeyEvent; | |
7 | +import android.view.LayoutInflater; | |
8 | +import android.view.MotionEvent; | |
9 | +import android.view.View; | |
10 | +import android.view.ViewGroup; | |
11 | +import android.view.animation.AlphaAnimation; | |
12 | +import android.view.animation.Animation; | |
13 | +import android.view.animation.Animation.AnimationListener; | |
14 | +import android.view.animation.ScaleAnimation; | |
15 | +import android.widget.LinearLayout; | |
16 | +import android.widget.RelativeLayout; | |
17 | + | |
18 | +import com.shunzhi.mychartlibrary.R; | |
19 | + | |
20 | + | |
21 | +public class HeadIconSelectorView extends RelativeLayout implements | |
22 | + GestureDetector.OnGestureListener { | |
23 | + | |
24 | + private View baseView; | |
25 | + | |
26 | + private RelativeLayout mainRl; | |
27 | + private LinearLayout bottomLl; | |
28 | + private LinearLayout cameraLl; | |
29 | + private LinearLayout galleryLl; | |
30 | + private LinearLayout cancelLl; | |
31 | + | |
32 | + private GestureDetector gestureDetector; // 手势检测器 | |
33 | + private boolean isAnimationing = false; | |
34 | + private OnHeadIconClickListener onHeadIconClickListener; | |
35 | + public static final int FROM_CAMERA = 2; | |
36 | + public static final int FROM_GALLERY = 3; | |
37 | + public static final int CANCEL = 4; | |
38 | + public static final int BLANK_CANCEL = 5; | |
39 | + | |
40 | + public HeadIconSelectorView(Context context) { | |
41 | + super(context); | |
42 | + init(); | |
43 | + } | |
44 | + | |
45 | + @SuppressLint("ClickableViewAccessibility") | |
46 | + private void init() { | |
47 | + findView(); | |
48 | + this.setOnTouchListener(new OnTouchListener() { | |
49 | + @Override | |
50 | + public boolean onTouch(View v, MotionEvent event) { | |
51 | + return gestureDetector.onTouchEvent(event); | |
52 | + } | |
53 | + }); | |
54 | + bottomLl.setVisibility(View.INVISIBLE); | |
55 | + mainRl.setOnClickListener(new OnClickListener() { | |
56 | + | |
57 | + @Override | |
58 | + public void onClick(View v) { | |
59 | + if (null != onHeadIconClickListener) { | |
60 | + onHeadIconClickListener.onClick(BLANK_CANCEL); | |
61 | + } | |
62 | + cancel(); | |
63 | + } | |
64 | + }); | |
65 | + cancelLl.setOnClickListener(new OnClickListener() { | |
66 | + | |
67 | + @Override | |
68 | + public void onClick(View v) { | |
69 | + if (null != onHeadIconClickListener) { | |
70 | + onHeadIconClickListener.onClick(CANCEL); | |
71 | + } | |
72 | + cancel(); | |
73 | + } | |
74 | + }); | |
75 | + cameraLl.setOnClickListener(new OnClickListener() { | |
76 | + | |
77 | + @Override | |
78 | + public void onClick(View v) { | |
79 | + if (null != onHeadIconClickListener) { | |
80 | + onHeadIconClickListener.onClick(FROM_CAMERA); | |
81 | + } | |
82 | + cancel(); | |
83 | + } | |
84 | + }); | |
85 | + galleryLl.setOnClickListener(new OnClickListener() { | |
86 | + | |
87 | + @Override | |
88 | + public void onClick(View v) { | |
89 | + | |
90 | + if (null != onHeadIconClickListener) { | |
91 | + onHeadIconClickListener.onClick(FROM_GALLERY); | |
92 | + } | |
93 | + cancel(); | |
94 | + } | |
95 | + }); | |
96 | + } | |
97 | + | |
98 | + @SuppressWarnings("deprecation") | |
99 | + private void findView() { | |
100 | + gestureDetector = new GestureDetector(this); | |
101 | + baseView = LayoutInflater.from(getContext()).inflate( | |
102 | + R.layout.layout_view_headicon, this); | |
103 | + mainRl = (RelativeLayout) baseView.findViewById(R.id.head_icon_main_rl); | |
104 | + bottomLl = (LinearLayout) baseView.findViewById(R.id.head_icon_main_ll); | |
105 | + cameraLl = (LinearLayout) baseView | |
106 | + .findViewById(R.id.head_icon_camera_ll); | |
107 | + galleryLl = (LinearLayout) baseView | |
108 | + .findViewById(R.id.head_icon_gallery_ll); | |
109 | + cancelLl = (LinearLayout) baseView | |
110 | + .findViewById(R.id.head_icon_cancel_ll); | |
111 | + } | |
112 | + | |
113 | + protected void bottomViewFlyIn() { | |
114 | + final ScaleAnimation sa1 = new ScaleAnimation(1, 1, 0, 1.2f, | |
115 | + Animation.RELATIVE_TO_SELF, 1, Animation.RELATIVE_TO_SELF, 1f); | |
116 | + sa1.setDuration(250); | |
117 | + final ScaleAnimation sa2 = new ScaleAnimation(1, 1, 1.2f, 1, | |
118 | + Animation.RELATIVE_TO_SELF, 1, Animation.RELATIVE_TO_SELF, 1f); | |
119 | + sa2.setDuration(150); | |
120 | + sa1.setAnimationListener(new AnimationListener() { | |
121 | + | |
122 | + @Override | |
123 | + public void onAnimationStart(Animation animation) { | |
124 | + isAnimationing = true; | |
125 | + bottomLl.setVisibility(VISIBLE); | |
126 | + } | |
127 | + | |
128 | + @Override | |
129 | + public void onAnimationRepeat(Animation animation) { | |
130 | + } | |
131 | + | |
132 | + @Override | |
133 | + public void onAnimationEnd(Animation animation) { | |
134 | + isAnimationing = false; | |
135 | + bottomLl.startAnimation(sa2); | |
136 | + } | |
137 | + }); | |
138 | + bottomLl.startAnimation(sa1); | |
139 | + } | |
140 | + | |
141 | + protected void bottomViewFlyOut() { | |
142 | + final ScaleAnimation sa1 = new ScaleAnimation(1, 1, 1, 1.2f, | |
143 | + Animation.RELATIVE_TO_SELF, 1, Animation.RELATIVE_TO_SELF, 1f); | |
144 | + sa1.setDuration(150); | |
145 | + final ScaleAnimation sa2 = new ScaleAnimation(1, 1, 1.2f, 0, | |
146 | + Animation.RELATIVE_TO_SELF, 1, Animation.RELATIVE_TO_SELF, 1f); | |
147 | + sa2.setDuration(250); | |
148 | + sa1.setAnimationListener(new AnimationListener() { | |
149 | + | |
150 | + @Override | |
151 | + public void onAnimationStart(Animation animation) { | |
152 | + isAnimationing = true; | |
153 | + bottomLl.setVisibility(VISIBLE); | |
154 | + } | |
155 | + | |
156 | + @Override | |
157 | + public void onAnimationRepeat(Animation animation) { | |
158 | + } | |
159 | + | |
160 | + @Override | |
161 | + public void onAnimationEnd(Animation animation) { | |
162 | + bottomLl.startAnimation(sa2); | |
163 | + } | |
164 | + }); | |
165 | + sa2.setAnimationListener(new AnimationListener() { | |
166 | + | |
167 | + @Override | |
168 | + public void onAnimationStart(Animation animation) { | |
169 | + } | |
170 | + | |
171 | + @Override | |
172 | + public void onAnimationRepeat(Animation animation) { | |
173 | + } | |
174 | + | |
175 | + @Override | |
176 | + public void onAnimationEnd(Animation animation) { | |
177 | + isAnimationing = false; | |
178 | + bottomLl.setVisibility(INVISIBLE); | |
179 | + flyOut(); | |
180 | + } | |
181 | + }); | |
182 | + bottomLl.startAnimation(sa1); | |
183 | + } | |
184 | + | |
185 | + protected void cancel() { | |
186 | + if (!isAnimationing) { | |
187 | + if (bottomLl.getVisibility() == VISIBLE) { | |
188 | + bottomViewFlyOut(); | |
189 | + return; | |
190 | + } | |
191 | + } | |
192 | + } | |
193 | + | |
194 | + public void flyIn() { | |
195 | + AlphaAnimation aa = new AlphaAnimation(0, 1); | |
196 | + aa.setDuration(300); | |
197 | + aa.setAnimationListener(new AnimationListener() { | |
198 | + | |
199 | + @Override | |
200 | + public void onAnimationStart(Animation animation) { | |
201 | + isAnimationing = true; | |
202 | + setVisibility(VISIBLE); | |
203 | + } | |
204 | + | |
205 | + @Override | |
206 | + public void onAnimationRepeat(Animation animation) { | |
207 | + } | |
208 | + | |
209 | + @Override | |
210 | + public void onAnimationEnd(Animation animation) { | |
211 | + isAnimationing = false; | |
212 | + bottomViewFlyIn(); | |
213 | + } | |
214 | + }); | |
215 | + startAnimation(aa); | |
216 | + } | |
217 | + | |
218 | + public void flyOut() { | |
219 | + AlphaAnimation aa = new AlphaAnimation(1, 0); | |
220 | + aa.setDuration(300); | |
221 | + aa.setAnimationListener(new AnimationListener() { | |
222 | + | |
223 | + @Override | |
224 | + public void onAnimationStart(Animation animation) { | |
225 | + isAnimationing = true; | |
226 | + setVisibility(VISIBLE); | |
227 | + } | |
228 | + | |
229 | + @Override | |
230 | + public void onAnimationRepeat(Animation animation) { | |
231 | + } | |
232 | + | |
233 | + @Override | |
234 | + public void onAnimationEnd(Animation animation) { | |
235 | + isAnimationing = false; | |
236 | + destroy(); | |
237 | + } | |
238 | + }); | |
239 | + startAnimation(aa); | |
240 | + } | |
241 | + | |
242 | + protected void destroy() { | |
243 | + if (this.getParent() != null) { | |
244 | + ((ViewGroup) this.getParent()).removeView(this); | |
245 | + } | |
246 | + } | |
247 | + | |
248 | + @Override | |
249 | + public boolean onKeyDown(int keyCode, KeyEvent event) { | |
250 | + if (keyCode == KeyEvent.KEYCODE_BACK) { | |
251 | + if (!isAnimationing) { | |
252 | + if (bottomLl.getVisibility() == VISIBLE) { | |
253 | + bottomViewFlyOut(); | |
254 | + return true; | |
255 | + } | |
256 | + } else { | |
257 | + return true; | |
258 | + } | |
259 | + } | |
260 | + return super.onKeyDown(keyCode, event); | |
261 | + } | |
262 | + | |
263 | + public OnHeadIconClickListener getOnHeadIconClickListener() { | |
264 | + return onHeadIconClickListener; | |
265 | + } | |
266 | + | |
267 | + public void setOnHeadIconClickListener( | |
268 | + OnHeadIconClickListener onHeadIconClickListener) { | |
269 | + this.onHeadIconClickListener = onHeadIconClickListener; | |
270 | + } | |
271 | + | |
272 | + public interface OnHeadIconClickListener { | |
273 | + public void onClick(int from); | |
274 | + } | |
275 | + | |
276 | + @SuppressLint("ClickableViewAccessibility") | |
277 | + @Override | |
278 | + public boolean onTouchEvent(MotionEvent event) { | |
279 | + return gestureDetector.onTouchEvent(event); | |
280 | + } | |
281 | + | |
282 | + @Override | |
283 | + public boolean onDown(MotionEvent e) { | |
284 | + // TODO Auto-generated method stub | |
285 | + return false; | |
286 | + } | |
287 | + | |
288 | + @Override | |
289 | + public void onShowPress(MotionEvent e) { | |
290 | + // TODO Auto-generated method stub | |
291 | + | |
292 | + } | |
293 | + | |
294 | + @Override | |
295 | + public boolean onSingleTapUp(MotionEvent e) { | |
296 | + // TODO Auto-generated method stub | |
297 | + return false; | |
298 | + } | |
299 | + | |
300 | + @Override | |
301 | + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, | |
302 | + float distanceY) { | |
303 | + // TODO Auto-generated method stub | |
304 | + return false; | |
305 | + } | |
306 | + | |
307 | + @Override | |
308 | + public void onLongPress(MotionEvent e) { | |
309 | + // TODO Auto-generated method stub | |
310 | + | |
311 | + } | |
312 | + | |
313 | + private float minVelocityY = 100f;// 10个像素每秒 | |
314 | + private float minDistanceY = 100f;// 100个像素 | |
315 | + | |
316 | + // 用户按下触摸屏、快速移动后松开,由1个MotionEvent ACTION_DOWN, | |
317 | + // 多个ACTION_MOVE, 1个ACTION_UP触发 | |
318 | + // e1:第1个ACTION_DOWN MotionEvent | |
319 | + // e2:最后一个ACTION_MOVE MotionEvent | |
320 | + // velocityX:X轴上的移动速度,像素/秒 | |
321 | + // velocityY:Y轴上的移动速度,像素/秒 | |
322 | + @Override | |
323 | + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, | |
324 | + float velocityY) { | |
325 | + // 手势从上到下且移动速度较快 | |
326 | + if (e2.getY() - e1.getY() > minDistanceY && velocityY > minVelocityY) { | |
327 | + cancel(); | |
328 | + } | |
329 | + return false; | |
330 | + } | |
331 | +} | ... | ... |
... | ... | @@ -0,0 +1,84 @@ |
1 | +package com.shunzhi.mychartlibrary.widget; | |
2 | + | |
3 | + | |
4 | + | |
5 | +import android.media.AudioManager; | |
6 | +import android.media.MediaPlayer; | |
7 | +import android.media.MediaPlayer.OnCompletionListener; | |
8 | +import android.media.MediaPlayer.OnErrorListener; | |
9 | + | |
10 | +import java.io.IOException; | |
11 | + | |
12 | +public class MediaManager { | |
13 | + | |
14 | + | |
15 | + private static MediaPlayer mPlayer; | |
16 | + | |
17 | + private static boolean isPause; | |
18 | + | |
19 | + public static void playSound(String filePathString, | |
20 | + OnCompletionListener onCompletionListener) { | |
21 | + // TODO Auto-generated method stub | |
22 | + if (mPlayer==null) { | |
23 | + mPlayer=new MediaPlayer(); | |
24 | + //保险起见,设置报错监听 | |
25 | + mPlayer.setOnErrorListener(new OnErrorListener() { | |
26 | + | |
27 | + @Override | |
28 | + public boolean onError(MediaPlayer mp, int what, int extra) { | |
29 | + // TODO Auto-generated method stub | |
30 | + mPlayer.reset(); | |
31 | + return false; | |
32 | + } | |
33 | + }); | |
34 | + }else { | |
35 | + mPlayer.reset();//就恢复 | |
36 | + } | |
37 | + | |
38 | + try { | |
39 | + mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); | |
40 | + mPlayer.setOnCompletionListener(onCompletionListener); | |
41 | + mPlayer.setDataSource(filePathString); | |
42 | + mPlayer.prepare(); | |
43 | + mPlayer.start(); | |
44 | + } catch (IllegalArgumentException e) { | |
45 | + // TODO Auto-generated catch block | |
46 | + e.printStackTrace(); | |
47 | + } catch (SecurityException e) { | |
48 | + // TODO Auto-generated catch block | |
49 | + e.printStackTrace(); | |
50 | + } catch (IllegalStateException e) { | |
51 | + // TODO Auto-generated catch block | |
52 | + e.printStackTrace(); | |
53 | + } catch (IOException e) { | |
54 | + // TODO Auto-generated catch block | |
55 | + e.printStackTrace(); | |
56 | + } | |
57 | + } | |
58 | + | |
59 | + //停止函数 | |
60 | + public static void pause(){ | |
61 | + if (mPlayer!=null&&mPlayer.isPlaying()) { | |
62 | + mPlayer.pause(); | |
63 | + isPause=true; | |
64 | + } | |
65 | + } | |
66 | + | |
67 | + //继续 | |
68 | + public static void resume() | |
69 | + { | |
70 | + if (mPlayer!=null&&isPause) { | |
71 | + mPlayer.start(); | |
72 | + isPause=false; | |
73 | + } | |
74 | + } | |
75 | + | |
76 | + | |
77 | + public static void release() | |
78 | + { | |
79 | + if (mPlayer!=null) { | |
80 | + mPlayer.release(); | |
81 | + mPlayer=null; | |
82 | + } | |
83 | + } | |
84 | +} | ... | ... |
... | ... | @@ -0,0 +1,250 @@ |
1 | +package com.shunzhi.mychartlibrary.widget.pulltorefresh; | |
2 | + | |
3 | +import android.annotation.SuppressLint; | |
4 | +import android.content.Context; | |
5 | +import android.graphics.Color; | |
6 | +import android.support.v4.view.ViewCompat; | |
7 | +import android.support.v4.widget.ViewDragHelper; | |
8 | +import android.util.AttributeSet; | |
9 | +import android.view.Gravity; | |
10 | +import android.view.MotionEvent; | |
11 | +import android.view.View; | |
12 | +import android.view.ViewGroup; | |
13 | +import android.widget.LinearLayout; | |
14 | +import android.widget.TextView; | |
15 | + | |
16 | +import com.shunzhi.mychartlibrary.utils.ScreenUtil; | |
17 | + | |
18 | + | |
19 | +/** | |
20 | + * Created by Mao Jiqing on 2016/9/27. | |
21 | + */ | |
22 | +public class PullToRefreshLayout extends LinearLayout { | |
23 | + private ViewDragHelper VDH; | |
24 | + private View myList; | |
25 | + private TextView pullText; | |
26 | + private pulltorefreshNotifier pullNotifier; | |
27 | + private boolean isPull = true; | |
28 | + | |
29 | + public PullToRefreshLayout(Context context, AttributeSet attrs) { | |
30 | + super(context, attrs); | |
31 | + // TODO Auto-generated constructor stub | |
32 | +// init(); | |
33 | + VDH = ViewDragHelper.create(this, 10.0f, new DragHelperCallback()); | |
34 | + } | |
35 | + | |
36 | + public void setSlideView(View view) { | |
37 | + init(view); | |
38 | + } | |
39 | + | |
40 | + private void init(View view) { | |
41 | + LayoutParams lp1 = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, | |
42 | + ViewGroup.LayoutParams.MATCH_PARENT); | |
43 | + myList = view; | |
44 | + myList.setBackgroundColor(Color.parseColor("#FFFFFF")); | |
45 | + myList.setLayoutParams(lp1); | |
46 | + LayoutParams lp2 = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ScreenUtil.dip2px(getContext(), 100)); | |
47 | + pullText = new TextView(getContext()); | |
48 | + pullText.setText("下拉加载更多"); | |
49 | + pullText.setBackgroundColor(Color.parseColor("#FFFFFF")); | |
50 | + pullText.setGravity(Gravity.CENTER); | |
51 | + pullText.setLayoutParams(lp2); | |
52 | + setOrientation(LinearLayout.VERTICAL); | |
53 | + addView(pullText); | |
54 | + addView(myList); | |
55 | + } | |
56 | + | |
57 | + public View returnMylist() { | |
58 | + return myList; | |
59 | + } | |
60 | + | |
61 | + @Override | |
62 | + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | |
63 | + measureChildren(widthMeasureSpec, heightMeasureSpec); | |
64 | + | |
65 | + int maxWidth = MeasureSpec.getSize(widthMeasureSpec); | |
66 | + int maxHeight = MeasureSpec.getSize(heightMeasureSpec); | |
67 | + setMeasuredDimension( | |
68 | + resolveSizeAndState(maxWidth, widthMeasureSpec, 0), | |
69 | + resolveSizeAndState(maxHeight, heightMeasureSpec, 0)); | |
70 | + } | |
71 | + | |
72 | + @Override | |
73 | + protected void onLayout(boolean changed, int l, int t, int r, int b) { | |
74 | + if (pullText.getTop() == 0) { | |
75 | + viewHeight = pullText.getMeasuredHeight(); | |
76 | + pullText.layout(l, 0, r, viewHeight); | |
77 | + myList.layout(l, 0, r, b); | |
78 | + pullText.offsetTopAndBottom(-viewHeight); | |
79 | + } else { | |
80 | + pullText.layout(l, pullText.getTop(), r, pullText.getBottom()); | |
81 | + myList.layout(l, myList.getTop(), r, myList.getBottom()); | |
82 | + } | |
83 | + } | |
84 | + | |
85 | + /** | |
86 | + * 这是View的方法,该方法不支持android低版本(2.2、2.3)的操作系统,所以手动复制过来以免强制退出 | |
87 | + */ | |
88 | + public static int resolveSizeAndState(int size, int measureSpec, | |
89 | + int childMeasuredState) { | |
90 | + int result = size; | |
91 | + int specMode = MeasureSpec.getMode(measureSpec); | |
92 | + int specSize = MeasureSpec.getSize(measureSpec); | |
93 | + switch (specMode) { | |
94 | + case MeasureSpec.UNSPECIFIED: | |
95 | + result = size; | |
96 | + break; | |
97 | + case MeasureSpec.AT_MOST: | |
98 | + if (specSize < size) { | |
99 | + result = specSize | MEASURED_STATE_TOO_SMALL; | |
100 | + } else { | |
101 | + result = size; | |
102 | + } | |
103 | + break; | |
104 | + case MeasureSpec.EXACTLY: | |
105 | + result = specSize; | |
106 | + break; | |
107 | + } | |
108 | + return result | (childMeasuredState & MEASURED_STATE_MASK); | |
109 | + } | |
110 | + | |
111 | + @Override | |
112 | + public boolean onInterceptTouchEvent(MotionEvent event) { | |
113 | + boolean shouldIntercept = VDH.shouldInterceptTouchEvent(event) && isPull; | |
114 | + return shouldIntercept; | |
115 | + } | |
116 | + | |
117 | + @SuppressLint("ClickableViewAccessibility") | |
118 | + @Override | |
119 | + public boolean onTouchEvent(MotionEvent event) { | |
120 | + VDH.processTouchEvent(event); | |
121 | + return true; | |
122 | + } | |
123 | + | |
124 | + /** | |
125 | + * 这是拖拽效果的主要逻辑 | |
126 | + */ | |
127 | + private class DragHelperCallback extends ViewDragHelper.Callback { | |
128 | + | |
129 | + @Override | |
130 | + public void onViewPositionChanged(View changedView, int left, int top, | |
131 | + int dx, int dy) { | |
132 | + int childIndex = 1; | |
133 | + if (changedView == myList) { | |
134 | + childIndex = 2; | |
135 | + } | |
136 | + onViewPosChanged(childIndex, top); | |
137 | + } | |
138 | + | |
139 | + @Override | |
140 | + public boolean tryCaptureView(View child, int pointerId) { | |
141 | + return true; | |
142 | + } | |
143 | + | |
144 | + @Override | |
145 | + public int getViewVerticalDragRange(View child) { | |
146 | + return 1; | |
147 | + } | |
148 | + | |
149 | + @Override | |
150 | + public void onViewReleased(View releasedChild, float xvel, float yvel) { | |
151 | + refreshOrNot(releasedChild, yvel); | |
152 | + } | |
153 | + | |
154 | + @Override | |
155 | + public int clampViewPositionVertical(View child, int top, int dy) { | |
156 | + int finalTop = top; | |
157 | + if (child == pullText) { | |
158 | + if (top > 0) { | |
159 | + finalTop = 0; | |
160 | + } | |
161 | + } else if (child == myList) { | |
162 | + if (top < 0) { | |
163 | + finalTop = 0; | |
164 | + } | |
165 | + if (top >= viewHeight) { | |
166 | + pullText.setText("松开加载"); | |
167 | + } else { | |
168 | + pullText.setText("下拉加载更多"); | |
169 | + } | |
170 | + } | |
171 | + return child.getTop() + (finalTop - child.getTop()) / 2; | |
172 | + } | |
173 | + } | |
174 | + | |
175 | + /** | |
176 | + * 滑动时view位置改变协调处理 | |
177 | + * | |
178 | + * @param viewIndex | |
179 | + * 滑动view的index(1或2) | |
180 | + * @param posTop | |
181 | + * 滑动View的top位置 | |
182 | + */ | |
183 | + private static int viewHeight; | |
184 | + | |
185 | + private void onViewPosChanged(int viewIndex, int posTop) { | |
186 | + if (viewIndex == 1) { | |
187 | + int offsetTopBottom = viewHeight + pullText.getTop() | |
188 | + - myList.getTop(); | |
189 | + myList.offsetTopAndBottom(offsetTopBottom); | |
190 | + } else if (viewIndex == 2) { | |
191 | + int offsetTopBottom = myList.getTop() - viewHeight | |
192 | + - pullText.getTop(); | |
193 | + pullText.offsetTopAndBottom(offsetTopBottom); | |
194 | + } | |
195 | + invalidate(); | |
196 | + } | |
197 | + | |
198 | + private void refreshOrNot(View releasedChild, float yvel) { | |
199 | + int finalTop = 0; | |
200 | + if (releasedChild == pullText) { | |
201 | + // 拖动第一个view松手 | |
202 | + if (yvel < -50) { | |
203 | + finalTop = 0; | |
204 | + } else { | |
205 | + finalTop = viewHeight; | |
206 | + } | |
207 | + } else { | |
208 | + // 拖动第二个view松手 | |
209 | + if (yvel > viewHeight - 5 || releasedChild.getTop() >= viewHeight) { | |
210 | + finalTop = viewHeight; | |
211 | + if (null != pullNotifier) { | |
212 | + pullNotifier.onPull(); | |
213 | + } | |
214 | + pullText.setText("正在加载"); | |
215 | + } | |
216 | + } | |
217 | + | |
218 | + if (VDH.smoothSlideViewTo(myList, 0, finalTop)) { | |
219 | + ViewCompat.postInvalidateOnAnimation(this); | |
220 | + } | |
221 | + } | |
222 | + | |
223 | + public void refreshComplete() { | |
224 | + if (VDH.smoothSlideViewTo(myList, 0, 0)) { | |
225 | + ViewCompat.postInvalidateOnAnimation(this); | |
226 | + } | |
227 | + } | |
228 | + | |
229 | + @Override | |
230 | + public void computeScroll() { | |
231 | + if (VDH.continueSettling(true)) { | |
232 | + ViewCompat.postInvalidateOnAnimation(this); | |
233 | + } | |
234 | + } | |
235 | + | |
236 | + public void setpulltorefreshNotifier(pulltorefreshNotifier pullNotifier) { | |
237 | + this.pullNotifier = pullNotifier; | |
238 | + } | |
239 | + | |
240 | + public interface pulltorefreshNotifier { | |
241 | + public void onPull(); | |
242 | + } | |
243 | + | |
244 | + /** | |
245 | + * 禁止下拉 | |
246 | + */ | |
247 | + public void setPullGone() { | |
248 | + isPull = false; | |
249 | + } | |
250 | +} | ... | ... |
... | ... | @@ -0,0 +1,63 @@ |
1 | +package com.shunzhi.mychartlibrary.widget.pulltorefresh; | |
2 | + | |
3 | +import android.content.Context; | |
4 | +import android.util.AttributeSet; | |
5 | +import android.view.MotionEvent; | |
6 | +import android.view.View; | |
7 | +import android.widget.ListView; | |
8 | + | |
9 | +/** | |
10 | + * Created by Mao Jiqing on 2016/10/10. | |
11 | + */ | |
12 | +public class PullToRefreshListView extends ListView { | |
13 | + boolean allowDragBottom = true; | |
14 | + float downY = 0; | |
15 | + boolean needConsumeTouch = true; | |
16 | + | |
17 | + public PullToRefreshListView(Context context) { | |
18 | + super(context); | |
19 | + setDivider(null); | |
20 | + } | |
21 | + | |
22 | + public PullToRefreshListView(Context context, AttributeSet attrs) { | |
23 | + super(context, attrs); | |
24 | + // TODO Auto-generated constructor stub | |
25 | + } | |
26 | + | |
27 | + @Override | |
28 | + public boolean dispatchTouchEvent(MotionEvent ev) { | |
29 | + if (ev.getAction() == MotionEvent.ACTION_DOWN) { | |
30 | + downY = ev.getRawY(); | |
31 | + needConsumeTouch = true; | |
32 | + if (getMyScrollY() == 0) { | |
33 | + allowDragBottom = true; | |
34 | + } else { | |
35 | + allowDragBottom = false; | |
36 | + } | |
37 | + } else if (ev.getAction() == MotionEvent.ACTION_MOVE) { | |
38 | + if (!needConsumeTouch) { | |
39 | + getParent().requestDisallowInterceptTouchEvent(false); | |
40 | + return false; | |
41 | + } else if (allowDragBottom) { | |
42 | + if (downY - ev.getRawY() < -2) { | |
43 | + needConsumeTouch = false; | |
44 | + getParent().requestDisallowInterceptTouchEvent(false); | |
45 | + return false; | |
46 | + } | |
47 | + } | |
48 | + } | |
49 | + getParent().requestDisallowInterceptTouchEvent(needConsumeTouch); | |
50 | + return super.dispatchTouchEvent(ev); | |
51 | + } | |
52 | + | |
53 | + public int getMyScrollY() { | |
54 | + View c = getChildAt(0); | |
55 | + if (c == null) { | |
56 | + return 0; | |
57 | + } | |
58 | + int firstVisiblePosition = getFirstVisiblePosition(); | |
59 | + int top = c.getTop(); | |
60 | + return -top + firstVisiblePosition * c.getHeight(); | |
61 | + } | |
62 | + | |
63 | +} | |
0 | 64 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,63 @@ |
1 | +package com.shunzhi.mychartlibrary.widget.pulltorefresh; | |
2 | + | |
3 | +import android.content.Context; | |
4 | +import android.support.v7.widget.LinearLayoutManager; | |
5 | +import android.support.v7.widget.RecyclerView; | |
6 | +import android.util.AttributeSet; | |
7 | +import android.view.MotionEvent; | |
8 | +import android.view.View; | |
9 | + | |
10 | +/** | |
11 | + * Created by Mao Jiqing on 2016/9/27. | |
12 | + */ | |
13 | +public class PullToRefreshRecyclerView extends RecyclerView { | |
14 | + boolean allowDragBottom = true; | |
15 | + float downY = 0; | |
16 | + boolean needConsumeTouch = true; | |
17 | + | |
18 | + public PullToRefreshRecyclerView(Context context) { | |
19 | + super(context); | |
20 | + } | |
21 | + | |
22 | + public PullToRefreshRecyclerView(Context context, AttributeSet attrs) { | |
23 | + super(context, attrs); | |
24 | + // TODO Auto-generated constructor stub | |
25 | + } | |
26 | + | |
27 | + @Override | |
28 | + public boolean dispatchTouchEvent(MotionEvent ev) { | |
29 | + if (ev.getAction() == MotionEvent.ACTION_DOWN) { | |
30 | + downY = ev.getRawY(); | |
31 | + needConsumeTouch = true; | |
32 | + if (getMyScrollY() == 0) { | |
33 | + allowDragBottom = true; | |
34 | + } else { | |
35 | + allowDragBottom = false; | |
36 | + } | |
37 | + } else if (ev.getAction() == MotionEvent.ACTION_MOVE) { | |
38 | + if (!needConsumeTouch) { | |
39 | + getParent().requestDisallowInterceptTouchEvent(false); | |
40 | + return false; | |
41 | + } else if (allowDragBottom) { | |
42 | + if (downY - ev.getRawY() < -2) { | |
43 | + needConsumeTouch = false; | |
44 | + getParent().requestDisallowInterceptTouchEvent(false); | |
45 | + return false; | |
46 | + } | |
47 | + } | |
48 | + } | |
49 | + getParent().requestDisallowInterceptTouchEvent(needConsumeTouch); | |
50 | + return super.dispatchTouchEvent(ev); | |
51 | + } | |
52 | + | |
53 | + public int getMyScrollY() { | |
54 | + View c = getChildAt(0); | |
55 | + if (c == null) { | |
56 | + return 0; | |
57 | + } | |
58 | + int firstVisiblePosition = ((LinearLayoutManager) getLayoutManager()).findFirstVisibleItemPosition(); | |
59 | + int top = c.getTop(); | |
60 | + return -top + firstVisiblePosition * c.getHeight(); | |
61 | + } | |
62 | + | |
63 | +} | |
0 | 64 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,80 @@ |
1 | +package com.shunzhi.mychartlibrary.widget.pulltorefresh; | |
2 | + | |
3 | +import android.content.Context; | |
4 | +import android.support.v7.widget.LinearLayoutManager; | |
5 | +import android.support.v7.widget.RecyclerView; | |
6 | +import android.util.Log; | |
7 | +import android.view.View; | |
8 | +import android.view.ViewGroup; | |
9 | + | |
10 | +/** | |
11 | + * Created by Mao Jiqing on 2016/9/30. | |
12 | + */ | |
13 | +public class WrapContentLinearLayoutManager extends LinearLayoutManager { | |
14 | + private int[] mMeasuredDimension = new int[2]; | |
15 | + private int recyclerHeight = 0; | |
16 | + private RecyclerView.Recycler recycler; | |
17 | + | |
18 | + public WrapContentLinearLayoutManager(Context context, int orientation, boolean reverseLayout) { | |
19 | + super(context, orientation, reverseLayout); | |
20 | + } | |
21 | + | |
22 | + //... constructor | |
23 | + @Override | |
24 | + public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { | |
25 | + try { | |
26 | + this.recycler = recycler; | |
27 | + super.onLayoutChildren(recycler, state); | |
28 | + } catch (IndexOutOfBoundsException e) { | |
29 | + Log.e("probe", "ERROR = " + e.getMessage()); | |
30 | + } | |
31 | + } | |
32 | + | |
33 | + public int getRecyclerHeight() { | |
34 | + if (recycler == null) { | |
35 | + return 0; | |
36 | + } | |
37 | + int height = 0; | |
38 | + for (int i = 0; i < getItemCount(); i++) { | |
39 | + measureScrapChild(recycler, i, | |
40 | + View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), | |
41 | + View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), | |
42 | + mMeasuredDimension); | |
43 | + | |
44 | + if (getOrientation() == HORIZONTAL) { | |
45 | + if (i == 0) { | |
46 | + height = mMeasuredDimension[1]; | |
47 | + } | |
48 | + } else { | |
49 | + height = height + mMeasuredDimension[1]; | |
50 | + } | |
51 | + } | |
52 | + recyclerHeight = height; | |
53 | + return recyclerHeight; | |
54 | + } | |
55 | + | |
56 | + private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec, | |
57 | + int heightSpec, int[] measuredDimension) { | |
58 | + try { | |
59 | + View view = recycler.getViewForPosition(0);//fix 动态添加时报IndexOutOfBoundsException | |
60 | + | |
61 | + if (view != null) { | |
62 | + RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams(); | |
63 | + | |
64 | + int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec, | |
65 | + getPaddingLeft() + getPaddingRight(), p.width); | |
66 | + | |
67 | + int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec, | |
68 | + getPaddingTop() + getPaddingBottom(), p.height); | |
69 | + | |
70 | + view.measure(childWidthSpec, childHeightSpec); | |
71 | + measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin; | |
72 | + measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin; | |
73 | + recycler.recycleView(view); | |
74 | + } | |
75 | + } catch (Exception e) { | |
76 | + e.printStackTrace(); | |
77 | + } finally { | |
78 | + } | |
79 | + } | |
80 | +} | |
0 | 81 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,37 @@ |
1 | +package com.shunzhi.mychartlibrary.widget.pulltorefresh.base; | |
2 | + | |
3 | +import android.content.Context; | |
4 | +import android.view.View; | |
5 | + | |
6 | +import com.shunzhi.mychartlibrary.widget.pulltorefresh.PullToRefreshListView; | |
7 | +import com.shunzhi.mychartlibrary.widget.pulltorefresh.PullToRefreshRecyclerView; | |
8 | + | |
9 | + | |
10 | +/** | |
11 | + * Created by Mao Jiqing on 2016/10/10. | |
12 | + */ | |
13 | +public class PullToRefreshView extends View { | |
14 | + | |
15 | + public static final int LISTVIEW = 0; | |
16 | + public static final int RECYCLERVIEW = 1; | |
17 | + | |
18 | + public PullToRefreshView(Context context) { | |
19 | + super(context); | |
20 | + } | |
21 | + | |
22 | + public View getSlideView(int slideViewType) { | |
23 | + View baseView = null; | |
24 | + switch (slideViewType) { | |
25 | + case LISTVIEW: | |
26 | + baseView = new PullToRefreshListView(getContext()); | |
27 | + break; | |
28 | + case RECYCLERVIEW: | |
29 | + baseView = new PullToRefreshRecyclerView(getContext()); | |
30 | + break; | |
31 | + default: | |
32 | + baseView = null; | |
33 | + break; | |
34 | + } | |
35 | + return baseView; | |
36 | + } | |
37 | +} | ... | ... |
... | ... | @@ -0,0 +1,11 @@ |
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<vector xmlns:tools="http://schemas.android.com/tools" | |
3 | + xmlns:android="http://schemas.android.com/apk/res/android" | |
4 | + android:width="24dp" | |
5 | + android:height="24dp" | |
6 | + android:viewportWidth="24.0" | |
7 | + android:viewportHeight="24.0"> | |
8 | + <path | |
9 | + android:fillColor="#fff" | |
10 | + android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z" /> | |
11 | +</vector> | |
0 | 12 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,10 @@ |
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<shape xmlns:android="http://schemas.android.com/apk/res/android" > | |
3 | + | |
4 | + <solid android:color="#eeeeee" /> <!-- 背景色solid --> | |
5 | + <stroke | |
6 | + android:width="1px" | |
7 | + android:color="#9b9b9b" /> <!-- 边框设置 --> | |
8 | + <corners android:radius="3dp" /> <!-- 转角 --> | |
9 | + | |
10 | +</shape> | |
0 | 11 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,10 @@ |
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<shape xmlns:android="http://schemas.android.com/apk/res/android" > | |
3 | + | |
4 | + <solid android:color="#ffffff" /> <!-- 背景色solid --> | |
5 | + <stroke | |
6 | + android:width="1px" | |
7 | + android:color="#9b9b9b" /> <!-- 边框设置 --> | |
8 | + <corners android:radius="3dp" /> <!-- 转角 --> | |
9 | + | |
10 | +</shape> | |
0 | 11 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,17 @@ |
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<selector xmlns:android="http://schemas.android.com/apk/res/android"> | |
3 | + | |
4 | + <item android:state_pressed="true"><shape> | |
5 | + <solid android:color="@color/click_bg" /> | |
6 | + </shape></item> | |
7 | + <item android:state_focused="true"><shape> | |
8 | + <solid android:color="@color/click_bg" /> | |
9 | + </shape></item> | |
10 | + <item android:state_enabled="true"><shape> | |
11 | + <solid android:color="@color/white" /> | |
12 | + </shape></item> | |
13 | + <item><shape> | |
14 | + <solid android:color="@color/white" /> | |
15 | + </shape></item> | |
16 | + | |
17 | +</selector> | |
0 | 18 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,9 @@ |
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<shape xmlns:android="http://schemas.android.com/apk/res/android" | |
3 | + android:shape="rectangle" > | |
4 | + | |
5 | + <solid android:color="@color/zz_divider"/> | |
6 | + | |
7 | + <size android:height="1dp" /> | |
8 | + | |
9 | +</shape> | |
0 | 10 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,156 @@ |
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
3 | + android:id="@+id/layout_tongbao_rl" | |
4 | + android:layout_width="match_parent" | |
5 | + android:layout_height="match_parent" | |
6 | + android:background="@android:color/white"> | |
7 | + | |
8 | + <com.shunzhi.mychartlibrary.widget.pulltorefresh.PullToRefreshLayout | |
9 | + android:id="@+id/content_lv" | |
10 | + android:layout_width="match_parent" | |
11 | + android:layout_height="match_parent" | |
12 | + android:layout_above="@+id/bottom_container_ll" | |
13 | + android:listSelector="@android:color/transparent" | |
14 | + android:orientation="vertical" /> | |
15 | + | |
16 | + <LinearLayout | |
17 | + android:id="@+id/bottom_container_ll" | |
18 | + android:layout_width="match_parent" | |
19 | + android:layout_height="wrap_content" | |
20 | + android:layout_alignParentBottom="true" | |
21 | + android:orientation="vertical"> | |
22 | + | |
23 | + <LinearLayout | |
24 | + android:id="@+id/tongbao_utils" | |
25 | + android:layout_width="match_parent" | |
26 | + android:layout_height="wrap_content" | |
27 | + android:background="@drawable/frame_bg" | |
28 | + android:orientation="horizontal" | |
29 | + android:paddingBottom="5dp" | |
30 | + android:paddingLeft="10dp" | |
31 | + android:paddingRight="10dp" | |
32 | + android:paddingTop="5dp"> | |
33 | + | |
34 | + <EditText | |
35 | + android:id="@+id/mess_et" | |
36 | + android:layout_width="0dp" | |
37 | + android:layout_height="wrap_content" | |
38 | + android:layout_gravity="center_vertical" | |
39 | + android:layout_weight="1" | |
40 | + android:background="@drawable/xmxq_tc_bj" | |
41 | + android:imeOptions="actionSend" | |
42 | + android:inputType="text" | |
43 | + android:padding="5dp" | |
44 | + android:textSize="16sp" /> | |
45 | + | |
46 | + <ImageView | |
47 | + android:id="@+id/voice_iv" | |
48 | + android:layout_width="wrap_content" | |
49 | + android:layout_height="wrap_content" | |
50 | + android:layout_gravity="center_vertical" | |
51 | + android:layout_marginLeft="5dp" | |
52 | + android:layout_marginRight="5dp" | |
53 | + android:visibility="gone" | |
54 | + android:background="@mipmap/voice_btn_normal" | |
55 | + android:padding="4dp" /> | |
56 | + | |
57 | + <com.shunzhi.mychartlibrary.widget.AudioRecordButton | |
58 | + android:id="@+id/voice_btn" | |
59 | + android:layout_width="0dp" | |
60 | + android:layout_height="wrap_content" | |
61 | + android:layout_gravity="center_vertical" | |
62 | + android:layout_margin="5dp" | |
63 | + android:layout_weight="1" | |
64 | + android:background="@drawable/button_recordnormal" | |
65 | + android:gravity="center" | |
66 | + android:minHeight="0dp" | |
67 | + android:padding="5dp" | |
68 | + android:text="@string/normal" | |
69 | + android:textColor="#727272" | |
70 | + android:visibility="gone"></com.shunzhi.mychartlibrary.widget.AudioRecordButton> | |
71 | + | |
72 | + <ImageView | |
73 | + android:id="@+id/emoji" | |
74 | + android:visibility="gone" | |
75 | + android:layout_width="wrap_content" | |
76 | + android:layout_height="wrap_content" | |
77 | + android:layout_gravity="center_vertical" | |
78 | + android:layout_marginLeft="5dp" | |
79 | + android:background="@mipmap/emoji" | |
80 | + android:padding="4dp" /> | |
81 | + | |
82 | + <ImageView | |
83 | + android:id="@+id/mess_iv" | |
84 | + android:layout_width="wrap_content" | |
85 | + android:layout_height="wrap_content" | |
86 | + android:layout_gravity="center_vertical" | |
87 | + android:layout_marginLeft="5dp" | |
88 | + android:visibility="gone" | |
89 | + android:background="@mipmap/tb_more" | |
90 | + android:padding="4dp" /> | |
91 | + </LinearLayout> | |
92 | + | |
93 | + <LinearLayout | |
94 | + android:id="@+id/emoji_group" | |
95 | + android:layout_width="match_parent" | |
96 | + android:layout_height="wrap_content" | |
97 | + android:background="@color/white" | |
98 | + android:orientation="vertical" | |
99 | + android:visibility="gone"> | |
100 | + | |
101 | + <android.support.v4.view.ViewPager | |
102 | + android:id="@+id/vPager" | |
103 | + android:layout_width="match_parent" | |
104 | + android:layout_height="150dp" | |
105 | + android:layout_marginTop="3dp" | |
106 | + android:background="@color/light_gray_2" /> | |
107 | + | |
108 | + <RelativeLayout | |
109 | + android:layout_width="match_parent" | |
110 | + android:layout_height="wrap_content"> | |
111 | + | |
112 | + <ImageView | |
113 | + android:layout_width="wrap_content" | |
114 | + android:layout_height="wrap_content" | |
115 | + android:layout_alignParentLeft="true" | |
116 | + android:background="@color/light_gray_2" | |
117 | + android:paddingBottom="5dp" | |
118 | + android:paddingLeft="5dp" | |
119 | + android:paddingRight="5dp" | |
120 | + android:paddingTop="5dp" | |
121 | + android:src="@mipmap/emoji_icon" /> | |
122 | + | |
123 | + <TextView | |
124 | + android:id="@+id/send_emoji_icon" | |
125 | + android:layout_width="wrap_content" | |
126 | + android:layout_height="wrap_content" | |
127 | + android:layout_alignParentRight="true" | |
128 | + android:background="@drawable/frame_blue_to_thin_bg" | |
129 | + android:paddingBottom="5dp" | |
130 | + android:paddingLeft="10dp" | |
131 | + android:paddingRight="10dp" | |
132 | + android:paddingTop="5dp" | |
133 | + android:text="发送" | |
134 | + android:textColor="@color/white" | |
135 | + android:textSize="16sp" /> | |
136 | + </RelativeLayout> | |
137 | + </LinearLayout> | |
138 | + | |
139 | + <FrameLayout | |
140 | + android:layout_width="match_parent" | |
141 | + android:layout_height="wrap_content"> | |
142 | + | |
143 | + <com.shunzhi.mychartlibrary.widget.ChatBottomView | |
144 | + android:id="@+id/other_lv" | |
145 | + android:layout_width="match_parent" | |
146 | + android:layout_height="200dp" | |
147 | + android:visibility="gone" /> | |
148 | + | |
149 | + <ListView | |
150 | + android:id="@+id/mess_lv" | |
151 | + android:layout_width="match_parent" | |
152 | + android:layout_height="wrap_content" | |
153 | + android:visibility="gone" /> | |
154 | + </FrameLayout> | |
155 | + </LinearLayout> | |
156 | +</RelativeLayout> | |
0 | 157 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,61 @@ |
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
3 | + android:layout_width="match_parent" | |
4 | + android:layout_height="match_parent" | |
5 | + android:background="@color/titleColor" | |
6 | + > | |
7 | + | |
8 | + <ImageView | |
9 | + android:id="@+id/ivLeft" | |
10 | + android:layout_width="wrap_content" | |
11 | + android:layout_height="match_parent" | |
12 | + android:layout_alignParentLeft="true" | |
13 | + android:layout_centerVertical="true" | |
14 | + android:focusable="true" | |
15 | + android:paddingLeft="10dp" | |
16 | + android:paddingRight="20dp" | |
17 | + android:src="@drawable/btn_back_dark_24dp" /> | |
18 | + | |
19 | + <TextView | |
20 | + android:id="@+id/tvTitle" | |
21 | + android:layout_width="wrap_content" | |
22 | + android:layout_height="wrap_content" | |
23 | + android:layout_centerInParent="true" | |
24 | + android:text="@string/app_name" | |
25 | + android:textColor="@color/white" | |
26 | + android:textSize="16sp" | |
27 | + android:textStyle="bold" /> | |
28 | + | |
29 | + <LinearLayout | |
30 | + android:id="@+id/llRight" | |
31 | + android:layout_width="wrap_content" | |
32 | + android:layout_height="match_parent" | |
33 | + android:layout_alignParentRight="true" | |
34 | + android:focusable="true" | |
35 | + android:gravity="center_vertical" | |
36 | + android:orientation="horizontal" | |
37 | + android:paddingLeft="20dp" | |
38 | + android:paddingRight="10dp" | |
39 | + android:visibility="gone"> | |
40 | + | |
41 | + <TextView | |
42 | + android:id="@+id/tvRight" | |
43 | + android:layout_width="wrap_content" | |
44 | + android:layout_height="match_parent" | |
45 | + android:layout_gravity="center_vertical" | |
46 | + android:gravity="center_vertical" | |
47 | + android:textColor="@color/white" | |
48 | + android:textSize="16sp" | |
49 | + android:textStyle="bold" | |
50 | + android:visibility="gone" /> | |
51 | + | |
52 | + <ImageView | |
53 | + android:id="@+id/ivRight" | |
54 | + android:layout_width="wrap_content" | |
55 | + android:layout_height="match_parent" | |
56 | + android:layout_gravity="center_vertical" | |
57 | + android:gravity="center_vertical" | |
58 | + android:visibility="gone" /> | |
59 | + </LinearLayout> | |
60 | + | |
61 | +</RelativeLayout> | |
0 | 62 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,21 @@ |
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
3 | + android:layout_width="match_parent" | |
4 | + android:layout_height="match_parent" | |
5 | + android:orientation="vertical" > | |
6 | + | |
7 | + <com.shunzhi.mychartlibrary.widget.ExpandGridView | |
8 | + android:id="@+id/gridview" | |
9 | + android:layout_width="match_parent" | |
10 | + android:layout_height="match_parent" | |
11 | + android:numColumns="7" | |
12 | + android:scrollbars="none" | |
13 | + android:verticalSpacing="5dp" | |
14 | + android:gravity="center" | |
15 | + android:layout_gravity="center" | |
16 | + android:layout_marginTop="6dp" | |
17 | + android:layout_marginBottom="6dp" | |
18 | + android:fadingEdge="none" | |
19 | + /> | |
20 | + | |
21 | +</LinearLayout> | ... | ... |
... | ... | @@ -0,0 +1,24 @@ |
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
3 | + android:layout_width="match_parent" | |
4 | + android:layout_height="wrap_content" | |
5 | + android:orientation="vertical" > | |
6 | + | |
7 | + <TextView | |
8 | + android:id="@+id/title" | |
9 | + android:layout_width="match_parent" | |
10 | + android:layout_height="wrap_content" | |
11 | + android:layout_gravity="center_vertical" | |
12 | + android:gravity="left" | |
13 | + android:paddingBottom="5dp" | |
14 | + android:paddingLeft="10dp" | |
15 | + android:paddingTop="5dp" | |
16 | + android:textColor="@color/black" /> | |
17 | + | |
18 | + <View | |
19 | + android:layout_width="match_parent" | |
20 | + android:layout_height="1dp" | |
21 | + android:layout_marginTop="5dp" | |
22 | + android:background="@drawable/item_divider_line" /> | |
23 | + | |
24 | +</LinearLayout> | |
0 | 25 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,9 @@ |
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<ImageView xmlns:android="http://schemas.android.com/apk/res/android" | |
3 | + android:id="@+id/iv_expression" | |
4 | + android:layout_width="wrap_content" | |
5 | + android:layout_height="wrap_content" | |
6 | + android:padding="8dp" | |
7 | + android:scaleType="centerInside"> | |
8 | + | |
9 | +</ImageView> | ... | ... |
... | ... | @@ -0,0 +1,70 @@ |
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
3 | + android:layout_width="match_parent" | |
4 | + android:layout_height="match_parent" | |
5 | + android:padding="10dp" | |
6 | + android:orientation="horizontal" > | |
7 | + <LinearLayout | |
8 | + android:id="@+id/image_bottom_group" | |
9 | + android:layout_width="0dp" | |
10 | + android:layout_height="wrap_content" | |
11 | + android:layout_gravity="center_horizontal" | |
12 | + android:layout_weight="1" | |
13 | + android:orientation="vertical" > | |
14 | + | |
15 | + <ImageView | |
16 | + android:layout_width="wrap_content" | |
17 | + android:layout_height="wrap_content" | |
18 | + android:layout_gravity="center_horizontal" | |
19 | + android:background="@mipmap/tb_bottom_images" /> | |
20 | + | |
21 | + <TextView | |
22 | + android:layout_width="wrap_content" | |
23 | + android:layout_height="wrap_content" | |
24 | + android:layout_gravity="center_horizontal" | |
25 | + android:text="图像" /> | |
26 | + </LinearLayout> | |
27 | + | |
28 | + <LinearLayout | |
29 | + android:id="@+id/camera_group" | |
30 | + android:layout_width="0dp" | |
31 | + android:layout_height="wrap_content" | |
32 | + android:layout_gravity="center_horizontal" | |
33 | + android:layout_weight="1" | |
34 | + android:orientation="vertical" > | |
35 | + | |
36 | + <ImageView | |
37 | + android:layout_width="wrap_content" | |
38 | + android:layout_height="wrap_content" | |
39 | + android:layout_gravity="center_horizontal" | |
40 | + android:background="@mipmap/tb_bottom_take_photo" /> | |
41 | + | |
42 | + <TextView | |
43 | + android:layout_width="wrap_content" | |
44 | + android:layout_height="wrap_content" | |
45 | + android:layout_gravity="center_horizontal" | |
46 | + android:text="照相" /> | |
47 | + </LinearLayout> | |
48 | + | |
49 | + <LinearLayout | |
50 | + android:id="@+id/phrase_group" | |
51 | + android:layout_width="0dp" | |
52 | + android:layout_height="wrap_content" | |
53 | + android:layout_gravity="center_horizontal" | |
54 | + android:layout_weight="1" | |
55 | + android:orientation="vertical" > | |
56 | + | |
57 | + <ImageView | |
58 | + android:layout_width="wrap_content" | |
59 | + android:layout_height="wrap_content" | |
60 | + android:layout_gravity="center_horizontal" | |
61 | + android:background="@mipmap/tb_bottom_offen" /> | |
62 | + | |
63 | + <TextView | |
64 | + android:layout_width="wrap_content" | |
65 | + android:layout_height="wrap_content" | |
66 | + android:layout_gravity="center_horizontal" | |
67 | + android:text="常用语" /> | |
68 | + </LinearLayout> | |
69 | + | |
70 | +</LinearLayout> | |
0 | 71 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,80 @@ |
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
3 | + android:id="@+id/head_icon_main_rl" | |
4 | + android:layout_width="match_parent" | |
5 | + android:layout_height="match_parent" | |
6 | + android:background="@color/zz_half_transparent" > | |
7 | + | |
8 | + <LinearLayout | |
9 | + android:id="@+id/head_icon_main_ll" | |
10 | + android:layout_width="match_parent" | |
11 | + android:layout_height="wrap_content" | |
12 | + android:layout_alignParentBottom="true" | |
13 | + android:layout_alignParentLeft="true" | |
14 | + android:background="@color/light_gray_2" | |
15 | + android:orientation="vertical" > | |
16 | + | |
17 | + <LinearLayout | |
18 | + android:id="@+id/head_icon_camera_ll" | |
19 | + android:layout_width="match_parent" | |
20 | + android:layout_height="wrap_content" | |
21 | + android:background="@drawable/click_bg" | |
22 | + android:gravity="center" > | |
23 | + | |
24 | + <TextView | |
25 | + android:layout_width="wrap_content" | |
26 | + android:layout_height="wrap_content" | |
27 | + android:layout_margin="10dp" | |
28 | + android:text="拍照" | |
29 | + android:textColor="@color/dark_gray_1" /> | |
30 | + </LinearLayout> | |
31 | + | |
32 | + <View | |
33 | + android:layout_width="match_parent" | |
34 | + android:layout_height="1dp" | |
35 | + android:background="@drawable/item_divider_line" /> | |
36 | + | |
37 | + <LinearLayout | |
38 | + android:id="@+id/head_icon_gallery_ll" | |
39 | + android:layout_width="match_parent" | |
40 | + android:layout_height="wrap_content" | |
41 | + android:background="@drawable/click_bg" | |
42 | + android:gravity="center" > | |
43 | + | |
44 | + <TextView | |
45 | + android:layout_width="wrap_content" | |
46 | + android:layout_height="wrap_content" | |
47 | + android:layout_margin="10dp" | |
48 | + android:text="从相册选择" | |
49 | + android:textColor="@color/dark_gray_1" /> | |
50 | + </LinearLayout> | |
51 | + | |
52 | + <View | |
53 | + android:layout_width="match_parent" | |
54 | + android:layout_height="1dp" | |
55 | + android:background="@drawable/item_divider_line" /> | |
56 | + | |
57 | + <View | |
58 | + android:layout_width="match_parent" | |
59 | + android:layout_height="1dp" | |
60 | + android:layout_marginTop="10dp" | |
61 | + android:background="@drawable/item_divider_line" /> | |
62 | + | |
63 | + <LinearLayout | |
64 | + android:id="@+id/head_icon_cancel_ll" | |
65 | + android:layout_width="match_parent" | |
66 | + android:layout_height="wrap_content" | |
67 | + android:background="@drawable/click_bg" | |
68 | + android:gravity="center" > | |
69 | + | |
70 | + <TextView | |
71 | + android:id="@+id/cancle" | |
72 | + android:layout_width="wrap_content" | |
73 | + android:layout_height="wrap_content" | |
74 | + android:layout_margin="10dp" | |
75 | + android:text="取消" | |
76 | + android:textColor="@color/dark_gray_1" /> | |
77 | + </LinearLayout> | |
78 | + </LinearLayout> | |
79 | + | |
80 | +</RelativeLayout> | |
0 | 81 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,36 @@ |
1 | +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
2 | + xmlns:tools="http://schemas.android.com/tools" | |
3 | + android:layout_width="wrap_content" | |
4 | + android:layout_height="wrap_content" | |
5 | + android:gravity="center" | |
6 | + android:orientation="vertical" > | |
7 | + | |
8 | + <LinearLayout | |
9 | + android:layout_width="wrap_content" | |
10 | + android:layout_height="wrap_content" | |
11 | + android:orientation="horizontal" > | |
12 | + | |
13 | + <ImageView | |
14 | + android:id="@+id/dialog_icon" | |
15 | + android:layout_width="wrap_content" | |
16 | + android:layout_height="wrap_content" | |
17 | + android:src="@mipmap/cancel" | |
18 | + android:visibility="gone" /> | |
19 | + | |
20 | + <ImageView | |
21 | + android:id="@+id/dialog_voice" | |
22 | + android:layout_width="wrap_content" | |
23 | + android:layout_height="wrap_content" | |
24 | + android:src="@mipmap/tb_voice1" | |
25 | + android:visibility="visible" /> | |
26 | + </LinearLayout> | |
27 | + | |
28 | + <TextView | |
29 | + android:id="@+id/recorder_dialogtext" | |
30 | + android:layout_width="wrap_content" | |
31 | + android:layout_height="wrap_content" | |
32 | + android:layout_marginTop="5dp" | |
33 | + android:text="@string/shouzhishanghua" | |
34 | + android:textColor="#ffffffff" /> | |
35 | + | |
36 | +</LinearLayout> | |
0 | 37 | \ No newline at end of file | ... | ... |
4.06 KB
3.79 KB
7.89 KB
2.24 KB
1.74 KB
1.81 KB
1.57 KB
1.42 KB
7.99 KB
7.99 KB
1.81 KB
1.59 KB
1.87 KB
3.02 KB
1.95 KB
2.25 KB
2.43 KB
3.96 KB
2.64 KB
3.34 KB
4.84 KB
1.78 KB
1.81 KB
7.24 KB
4.39 KB
2.13 KB
1.43 KB
1.21 KB
1.68 KB
1.8 KB
1.14 KB
2.54 KB
1.39 KB
1.85 KB
1.28 KB
1.98 KB
3.19 KB
3.9 KB
4.92 KB
3.37 KB
3.34 KB
4.91 KB
1.72 KB
3.01 KB
2.87 KB
1.18 KB
2.45 KB
2.04 KB
2.42 KB
2.41 KB
1.21 KB
1.6 KB
2.32 KB
... | ... | @@ -0,0 +1,157 @@ |
1 | +<?xml version="1.0" encoding="utf-8"?> | |
2 | +<resources> | |
3 | + <color name="colorPrimary">#3F51B5</color> | |
4 | + <color name="colorPrimaryDark">#303F9F</color> | |
5 | + <color name="colorAccent">#FF4081</color> | |
6 | + <color name="three_transparent">#30ffffff</color> | |
7 | + <color name="black">#000000</color> | |
8 | + <color name="white">#ffffff</color> | |
9 | + <color name="light_gray_1">#e5e5e5</color> | |
10 | + <color name="light_gray_2">#f0f2f6</color> | |
11 | + <color name="light_gray_3">#fafafa</color> | |
12 | + <color name="light_gray_4">#f5f5f5</color> | |
13 | + <color name="light_gray_5">#f3f3f3</color> | |
14 | + <color name="light_gray_6">#aaaaaa</color> | |
15 | + <color name="light_gray_7">#f0f0f0</color> | |
16 | + <color name="light_gray_8">#666666</color> | |
17 | + <color name="light_gray_9">#f4f5f7</color> | |
18 | + <color name="light_gray_10">#bfbfbf</color> | |
19 | + <color name="light_gray_11">#f1f2f6</color> | |
20 | + <color name="light_gray_12">#333333</color> | |
21 | + <color name="middle_gray_1">#999999</color> | |
22 | + <color name="middle_gray_2">#818181</color> | |
23 | + <color name="dark_gray_1">#051b28</color> | |
24 | + <color name="dark_gray_2">#848689</color> | |
25 | + <color name="dark_gray_3">#252525</color> | |
26 | + <color name="dark_gray_4">#232326</color> | |
27 | + <color name="dark_gray_5">#f2f4f5</color> | |
28 | + | |
29 | + <color name="blue2">#0a85ff</color> | |
30 | + <color name="blue3">#356cb0</color> | |
31 | + <color name="blue4">#5795f3</color> | |
32 | + <color name="blue5">#2297fe</color> | |
33 | + | |
34 | + <color name="yellow">#edbb74</color> | |
35 | + <color name="yellow_1">#ffb802</color> | |
36 | + <color name="yellow_2">#fff5e5</color> | |
37 | + <color name="yellow_3">#fd9c00</color> | |
38 | + <color name="red">#ffdd2727</color> <!-- 酱红色 --> | |
39 | + <color name="red1">#c82300</color> <!-- 深红色 --> | |
40 | + <color name="red2">#e64a4b</color> | |
41 | + <color name="red3">#ff4719</color> | |
42 | + <color name="red4">#f2426c</color> | |
43 | + <color name="red5">#ff7870</color> | |
44 | + <color name="red6">#dd2727</color> | |
45 | + <color name="red7">#ff4258</color> | |
46 | + <color name="red8">#e72701</color> | |
47 | + | |
48 | + <color name="mjq_red">#ff5757</color> | |
49 | + <color name="mjq_albumback">#E1E0DE</color> | |
50 | + <color name="mjq_none_color">#00000000</color> | |
51 | + <color name="click_bg">#d9d9d9</color> | |
52 | + <color name="edit_frame_bg">#e9eaec</color> | |
53 | + <color name="light_blue1">#3097e6</color> | |
54 | + <color name="light_blue2">#503097e6</color> | |
55 | + <color name="light_blue3">#dcf4ff</color> | |
56 | + <color name="light_blue4">#84d4f9</color> | |
57 | + <color name="light_blue5">#45b1e3</color> | |
58 | + <color name="light_blue6">#3299e8</color> | |
59 | + <color name="light_blue7">#1597f2</color> | |
60 | + | |
61 | + <color name="zhu_light_blue">#346cb0</color> | |
62 | + | |
63 | + <color name="zz_light_blue">#278ff3</color> | |
64 | + <color name="zz_divider">#e6e6e6</color> | |
65 | + <color name="zz_divider1">#dedede</color> | |
66 | + <color name="zz_invest_light_gray">#808080</color> | |
67 | + <color name="zz_half_transparent">#7f000000</color> | |
68 | + <color name="black_30_transparent">#48000000</color> | |
69 | + <color name="black_50_transparent">#50000000</color> | |
70 | + <color name="zz_seven_transparent">#70ffffff</color> | |
71 | + <color name="zz_light_gray_6">#ebebeb</color> | |
72 | + <color name="zz_4_11_16">#bbbbbb</color> | |
73 | + <color name="zz_gray_22">#222222</color> | |
74 | + <color name="text_color_gray1">#626262</color> | |
75 | + <color name="lines_view">#cccccc</color> | |
76 | + <color name="navpage">#FFE1E8EB</color> | |
77 | + <color name="dark_yellow_1">#ffb84c</color> | |
78 | + <color name="dark_white_1">#feeedc</color> | |
79 | + <color name="hint_red_1">#fadcdc</color> | |
80 | + <color name="black1">#2f2f2f</color> | |
81 | + <color name="black2">#656565</color> | |
82 | + <color name="black3">#595959</color> | |
83 | + <color name="black4">#343434</color> | |
84 | + <color name="light_blue_1">#4ca4fe</color> | |
85 | + <color name="light_blue_2">#14ccca</color> | |
86 | + <color name="light_red_1">#f26464</color> | |
87 | + <color name="light_blue">#1597f2</color> | |
88 | + | |
89 | + <color name="light_gray_13">#dddddd</color> | |
90 | + <color name="light_gray_14">#838383</color> | |
91 | + <color name="light_gray_15">#999999</color> | |
92 | + <color name="light_gray_16">#f2f5f5</color> | |
93 | + <color name="light_gray_17">#f8f8f8</color> | |
94 | + <color name="light_gray_18">#c9c7c3</color> | |
95 | + <color name="light_gray_19">#b2b2b2</color> | |
96 | + <color name="light_gray_21">#a3a8ad</color> | |
97 | + <color name="light_gray_20">#d2d2d2</color> | |
98 | + <color name="light_gray_22">#b3b3b3</color> | |
99 | + <color name="light_gray_24">#a5a5a5</color> | |
100 | + <color name="light_gray_23">#929292</color> | |
101 | + <color name="light_gray_25">#e0e0e0</color> | |
102 | + <color name="red_dark">#634444</color> | |
103 | + | |
104 | + <item name="subscribe_item_text_color_normal" type="color">@color/default_text</item> | |
105 | + | |
106 | + <color name="subscribe_item_text_color_pressed">#ffb9b9b9</color> | |
107 | + <color name="default_text">#ff454545</color> | |
108 | + <color name="subscribe_item_text_color_pressed_night">#ff303030</color> | |
109 | + <color name="subscribe_item_focused_stroke">#ffd9d9d9</color> | |
110 | + <color name="subscribe_item_drag_stroke">#ffd2d2d2</color> | |
111 | + <color name="subscribe_item_drag_bg">#fff5f5f5</color> | |
112 | + <color name="subscribe_item_drag_stroke_night">#ff464646</color> | |
113 | + <color name="subscribe_item_drag_bg_night">#ff252525</color> | |
114 | + <color name="subscribe_item_selected_bg">#ffffffff</color> | |
115 | + <color name="subscribe_item_selected_stroke">#ffcc3131</color> | |
116 | + <color name="subscribe_item_disabled_bg">#ffefefef</color> | |
117 | + <color name="subscribe_item_disabled_stroke">#ffd9d9d9</color> | |
118 | + <color name="subscribe_item_pressed_bg">#fff9f9f9</color> | |
119 | + <color name="subscribe_item_pressed_stroke">#ffcdcdcd</color> | |
120 | + <color name="subscribe_item_normal_bg">#fff5f5f5</color> | |
121 | + <color name="subscribe_item_normal_stroke">#ffcdcdcd</color> | |
122 | + <color name="subscribe_item_focused_bg_night">#ff252525</color> | |
123 | + <color name="subscribe_item_focused_stroke_night">#ff464646</color> | |
124 | + <color name="subscribe_item_selected_bg_night">#ff252525</color> | |
125 | + <color name="subscribe_item_selected_stroke_night">#ffbc494d</color> | |
126 | + <color name="subscribe_item_disabled_bg_night">#ff2b2b2b</color> | |
127 | + <color name="project_detail_red">#ffcd2323</color> | |
128 | + <color name="project_detail_purple">#ff573535</color> | |
129 | + <color name="transparentWhite">#30ffffff</color> | |
130 | + <color name="transparentWhit2">#efffffff</color> | |
131 | + <color name="transparentGray">#e6e0e0e0</color> | |
132 | + | |
133 | + <color name="hintTextColor">#494947</color> | |
134 | + <color name="bottomline">#B8B8B9</color> | |
135 | + <color name="bg_main">#F0EFF5</color> | |
136 | + | |
137 | + <color name="textRed">#FC5B6A</color> | |
138 | + | |
139 | + <color name="blue">#2956FE</color> | |
140 | + <color name="green">#00CB87</color> | |
141 | + <color name="back_top">#6d9bff</color> | |
142 | + <color name="textBlue">#ACC9FC</color> | |
143 | + <color name="titleColor">#6d9bff</color> | |
144 | + <color name="bgColor">#F0EFF5</color> | |
145 | + <color name="textColor">#494947</color> | |
146 | + <color name="xueqing_blue">#ABC9FF</color> | |
147 | + <color name="zxlx">#1BE2E5</color> | |
148 | + <color name="huodong_blue">#ACD1FB</color> | |
149 | + <color name="text_color">#757575</color> | |
150 | + <color name="textGreen">#5FB762</color> | |
151 | + <color name="transparent">#00000000</color> | |
152 | + <color name="deyu_textColor">#60b3f6</color> | |
153 | + <color name="deyu_BlueColor">#2b71c4</color> | |
154 | + <color name="line_color">#80bebebe</color> | |
155 | + | |
156 | + <color name="backgroud_null">#00000000</color> | |
157 | +</resources> | ... | ... |
... | ... | @@ -0,0 +1,101 @@ |
1 | +<resources> | |
2 | + | |
3 | + <!-- Default screen margins, per the Android Design guidelines. --> | |
4 | + <dimen name="activity_horizontal_margin">16dp</dimen> | |
5 | + <dimen name="activity_vertical_margin">16dp</dimen> | |
6 | + | |
7 | + <!-- margin --> | |
8 | + <dimen name="margin_tiny">4dp</dimen> | |
9 | + <dimen name="margin_small">8dp</dimen> | |
10 | + <dimen name="margin_medium">16dp</dimen> | |
11 | + <dimen name="margin_large">32dp</dimen> | |
12 | + <dimen name="margin_huge">64dp</dimen> | |
13 | + <dimen name="margin_only_txt">48dp</dimen> | |
14 | + <dimen name="detail_image_height">260dp</dimen> | |
15 | + | |
16 | + <!-- txtsize --> | |
17 | + <dimen name="txtsize_display1">34dp</dimen> | |
18 | + <dimen name="txtsize_num">36dp</dimen> | |
19 | + <dimen name="txtsize_headline">24dp</dimen> | |
20 | + <dimen name="txtsize_title">20dp</dimen> | |
21 | + <dimen name="txtsize_subhead">16dp</dimen> | |
22 | + <dimen name="txtsize_body">14dp</dimen> | |
23 | + <dimen name="txtsize_caption">12dp</dimen> | |
24 | + | |
25 | + <!-- other size --> | |
26 | + <dimen name="corner_radius">2dp</dimen> | |
27 | + <dimen name="banner_height">136dp</dimen> | |
28 | + | |
29 | + <dimen name="def_height">50dp</dimen> | |
30 | + <dimen name="avatarSize">50dp</dimen> | |
31 | + <dimen name="smallSpace">6dp</dimen> | |
32 | + | |
33 | + <dimen name="dp_066">0.66dp</dimen> | |
34 | + <dimen name="dp_2">2dp</dimen> | |
35 | + <dimen name="dp_4">4dp</dimen> | |
36 | + <dimen name="dp_5">5dp</dimen> | |
37 | + <dimen name="dp_8">8dp</dimen> | |
38 | + <dimen name="dp_10">10dp</dimen> | |
39 | + <dimen name="dp_14">14dp</dimen> | |
40 | + <dimen name="dp_16">16dp</dimen> | |
41 | + <dimen name="dp_22">22dp</dimen> | |
42 | + <dimen name="dp_24">24dp</dimen> | |
43 | + <dimen name="dp_26">26dp</dimen> | |
44 | + | |
45 | + <dimen name="dp_30">30dp</dimen> | |
46 | + <dimen name="dp_36">36dp</dimen> | |
47 | + <dimen name="dp_40">40dp</dimen> | |
48 | + <dimen name="dp_60">60dp</dimen> | |
49 | + <dimen name="dp_72">72dp</dimen> | |
50 | + | |
51 | + <dimen name="sp_12">12sp</dimen> | |
52 | + <dimen name="sp_14">14sp</dimen> | |
53 | + <dimen name="sp_16">16dp</dimen> | |
54 | + <dimen name="sp_18">18sp</dimen> | |
55 | + | |
56 | + <dimen name="textSize10">10dp</dimen> | |
57 | + <dimen name="textSize12">12dp</dimen> | |
58 | + <dimen name="textSize14">14dp</dimen> | |
59 | + <dimen name="textSize16">16dp</dimen> | |
60 | + <dimen name="textSize18">18dp</dimen> | |
61 | + <dimen name="textSize20">20dp</dimen> | |
62 | + <dimen name="textSize24">24dp</dimen> | |
63 | + <dimen name="textSize30">30dp</dimen> | |
64 | + <dimen name="size_dp_1">1dp</dimen> | |
65 | + <dimen name="size_dp_2">2dp</dimen> | |
66 | + <dimen name="size_dp_3">3dp</dimen> | |
67 | + <dimen name="size_dp_4">4dp</dimen> | |
68 | + <dimen name="size_dp_5">5dp</dimen> | |
69 | + <dimen name="size_dp_6">6dp</dimen> | |
70 | + <dimen name="size_dp_7">7dp</dimen> | |
71 | + <dimen name="size_dp_8">8dp</dimen> | |
72 | + <dimen name="size_dp_9">9dp</dimen> | |
73 | + <dimen name="size_dp_10">10dp</dimen> | |
74 | + <dimen name="size_dp_11">11dp</dimen> | |
75 | + <dimen name="size_dp_12">12dp</dimen> | |
76 | + <dimen name="size_dp_13">13dp</dimen> | |
77 | + <dimen name="size_dp_14">14dp</dimen> | |
78 | + <dimen name="size_dp_15">15dp</dimen> | |
79 | + <dimen name="size_dp_16">16dp</dimen> | |
80 | + <dimen name="size_dp_17">17.0dp</dimen> | |
81 | + <dimen name="size_dp_18">18.0dp</dimen> | |
82 | + <dimen name="size_dp_19">19dp</dimen> | |
83 | + <dimen name="size_dp_20">20dp</dimen> | |
84 | + <dimen name="size_dp_24">24dp</dimen> | |
85 | + <dimen name="size_dp_25">25dp</dimen> | |
86 | + <dimen name="size_dp_30">30dp</dimen> | |
87 | + <dimen name="size_dp_32">32dp</dimen> | |
88 | + <dimen name="size_dp_40">40dp</dimen> | |
89 | + <dimen name="size_dp_50">50dp</dimen> | |
90 | + <dimen name="size_dp_60">60dp</dimen> | |
91 | + <dimen name="size_dp_80">80dp</dimen> | |
92 | + <dimen name="size_dp_100">100dp</dimen> | |
93 | + <dimen name="size_dp_110">110dp</dimen> | |
94 | + <dimen name="size_dp_120">120dp</dimen> | |
95 | + <dimen name="size_dp_150">150dp</dimen> | |
96 | + <dimen name="size_dp_200">200dp</dimen> | |
97 | + <dimen name="size_dp_250">250dp</dimen> | |
98 | + <dimen name="size_dp_300">300dp</dimen> | |
99 | + <dimen name="size_dp_310">310dp</dimen> | |
100 | + | |
101 | +</resources> | |
0 | 102 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,10 @@ |
1 | +<resources> | |
2 | + <string name="app_name">MyChartLibrary</string> | |
3 | + <!-- 录音 --> | |
4 | + <string name="normal">按住 说话</string> | |
5 | + <string name="recording">松开 结束</string> | |
6 | + <string name="want_to_cancle">松开手指,取消发送</string> | |
7 | + <string name="shouzhishanghua">手指上滑,取消发送</string> | |
8 | + <string name="tooshort">录音时间过短</string> | |
9 | + <string name="toolong">录音时间过长</string> | |
10 | +</resources> | ... | ... |
... | ... | @@ -0,0 +1,97 @@ |
1 | +<resources> | |
2 | + | |
3 | + <!-- Base application theme. --> | |
4 | + <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> | |
5 | + <!-- Customize your theme here. --> | |
6 | + <item name="colorPrimary">@color/colorPrimary</item> | |
7 | + <item name="colorPrimaryDark">@color/colorPrimaryDark</item> | |
8 | + <item name="colorAccent">@color/colorAccent</item> | |
9 | + </style> | |
10 | + | |
11 | + <style name="dialog" parent="Theme.AppCompat.Light.Dialog.Alert"> | |
12 | + <item name="colorPrimary">@color/colorPrimary</item> | |
13 | + <item name="colorAccent">@color/colorAccent</item> | |
14 | + <item name="colorPrimaryDark">@color/colorPrimaryDark</item> | |
15 | + <item name="android:windowFrame">@null</item> | |
16 | + <item name="android:windowIsFloating">true</item> | |
17 | + <item name="android:windowIsTranslucent">false</item> | |
18 | + <item name="android:windowNoTitle">true</item> | |
19 | + <item name="android:background">@android:color/transparent</item> | |
20 | + <item name="android:windowBackground">@android:color/transparent</item> | |
21 | + <item name="android:backgroundDimEnabled">true</item> | |
22 | + </style> | |
23 | + | |
24 | + <style name="AlertDialogCustom" parent="Theme.AppCompat.Light.Dialog.Alert"> | |
25 | + <item name="colorPrimary">@color/colorPrimary</item> | |
26 | + <item name="colorAccent">@color/colorAccent</item> | |
27 | + <item name="colorPrimaryDark">@color/colorPrimaryDark</item> | |
28 | + </style> | |
29 | + | |
30 | + <style name="DialogTips" parent="Theme.AppCompat.Light.Dialog.Alert"> | |
31 | + <item name="colorPrimary">@color/colorPrimary</item> | |
32 | + <item name="colorAccent">@color/colorAccent</item> | |
33 | + <item name="colorPrimaryDark">@color/colorPrimaryDark</item> | |
34 | + <item name="android:gravity">center</item> | |
35 | + <item name="android:windowBackground">@color/transparent</item> | |
36 | + <item name="android:windowCloseOnTouchOutside">false</item> | |
37 | + </style> | |
38 | + | |
39 | + <style name="TextView_Wrap_16"> | |
40 | + <item name="android:layout_width">wrap_content</item> | |
41 | + <item name="android:layout_height">wrap_content</item> | |
42 | + <item name="android:textSize">@dimen/textSize16</item> | |
43 | + </style> | |
44 | + | |
45 | + <style name="TextView_Width_Match_16"> | |
46 | + <item name="android:layout_width">match_parent</item> | |
47 | + <item name="android:layout_height">wrap_content</item> | |
48 | + <item name="android:textSize">@dimen/textSize16</item> | |
49 | + </style> | |
50 | + | |
51 | + <style name="TextView_Height_Match_16"> | |
52 | + <item name="android:layout_width">wrap_content</item> | |
53 | + <item name="android:layout_height">match_parent</item> | |
54 | + <item name="android:textSize">@dimen/textSize16</item> | |
55 | + </style> | |
56 | + | |
57 | + <style name="TextView_Match_16"> | |
58 | + <item name="android:layout_width">match_parent</item> | |
59 | + <item name="android:layout_height">match_parent</item> | |
60 | + <item name="android:textSize">@dimen/textSize16</item> | |
61 | + </style> | |
62 | + <style name="MyProgressDialog" parent="@android:style/Theme.Dialog"> | |
63 | + <item name="android:windowBackground">@color/transparent</item> | |
64 | + <item name="android:windowFrame">@color/transparent</item> | |
65 | + <item name="android:windowNoTitle">true</item> | |
66 | + <item name="android:windowIsFloating">true</item> | |
67 | + <item name="android:windowIsTranslucent">true</item> | |
68 | + <item name="android:backgroundDimEnabled">true</item> | |
69 | + </style> | |
70 | + | |
71 | + <style name="AppTheme.ToolbarPopupOverlay" parent="ThemeOverlay.AppCompat.Light"> | |
72 | + <item name="overlapAnchor">false</item> | |
73 | + </style> | |
74 | + | |
75 | + <style name="TextAppearance.ExpandedTitle" parent="TextAppearance.AppCompat.Widget.ActionBar.Title"> | |
76 | + <item name="android:textSize">26sp</item> | |
77 | + </style> | |
78 | + | |
79 | + <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar"> | |
80 | + <!--<item name="colorPrimary">@color/colorPrimary</item>--> | |
81 | + <!--<item name="colorPrimaryDark">@color/colorPrimaryDark</item>--> | |
82 | + <!--<item name="colorAccent">@color/colorAccent</item>--> | |
83 | + </style> | |
84 | + | |
85 | + <style name="AppBarTheme" parent="android:Theme.Holo.Light"> | |
86 | + <item name="android:windowFullscreen">false</item> | |
87 | + <item name="android:windowIsTranslucent">true</item> | |
88 | + </style> | |
89 | + | |
90 | + <style name="Theme_audioDialog" parent="@android:style/Theme.Dialog"> | |
91 | + <item name="android:windowBackground">@mipmap/tb_dialog_loading_bg</item> | |
92 | + <item name="android:windowFrame">@null</item> | |
93 | + <item name="android:windowIsFloating">true</item> | |
94 | + <item name="android:windowIsTranslucent">true</item> | |
95 | + <item name="android:backgroundDimEnabled">false</item> | |
96 | + </style> | |
97 | +</resources> | ... | ... |
... | ... | @@ -0,0 +1,17 @@ |
1 | +package com.shunzhi.mychartlibrary; | |
2 | + | |
3 | +import org.junit.Test; | |
4 | + | |
5 | +import static org.junit.Assert.*; | |
6 | + | |
7 | +/** | |
8 | + * Example local unit test, which will execute on the development machine (host). | |
9 | + * | |
10 | + * @see <a href="http://d.android.com/tools/testing">Testing documentation</a> | |
11 | + */ | |
12 | +public class ExampleUnitTest { | |
13 | + @Test | |
14 | + public void addition_isCorrect() { | |
15 | + assertEquals(4, 2 + 2); | |
16 | + } | |
17 | +} | |
0 | 18 | \ No newline at end of file | ... | ... |